【问题标题】:Compile Time Template restriction C++编译时模板限制 C++
【发布时间】:2015-07-27 13:03:19
【问题描述】:

基本上我有 4 个类:

  • 过空
  • Meta:继承 OverVoid
  • 物理:与上述无关
  • Move:一个模板类

我希望 move 的模板只接受 OverVoid 类型的对象,即 OverVoid 和 Meta。

class OverVoid{
public:

    virtual ~OverVoid(){
    };
};

class Meta: public OverVoid{

};

class Physical{
public:
};

template<typename _Ty>
class Move{

};

我希望在编译时出现错误, 我知道有一种提升方式,但我不能使用 Boost(我公司的开发问题)

有什么想法吗?

【问题讨论】:

  • 也许在 OverVoid 类中放一个标签,然后在模板中做一个静态断言
  • 什么是“容器”?它不在您的代码中...

标签: c++ templates inheritance polymorphism


【解决方案1】:

使用std::enable_if:

template <typename T>
struct is_overvoid_or_meta
{
     static const bool value = false;
};

template <> struct is_overvoid_or_meta<OverVoid>
{
     static const bool value = true;
};

template <> struct is_overvoid_or_meta<Meta>
{
     static const bool value = true;
};

//Add specialization for all valid types - this allows you to more precisely tell, what types can be used as a template argument for Move

然后:

template<typename _Ty>
class Move
{
     typedef std::enable_if<is_overvoid_or_meta<_Ty>::value, _Ty>::type Type;
};

您将收到每种类型的编译时错误,不是OverVoid 或Meta(或者,更一般地说,对于每个T,其中is_overvoid_or_meta&lt;T&gt;::value 是false - 如果您要添加将来更多,您可能希望将is_overvoid_or_meta 更改为更通用的,例如is_acceptable_by_move 或其他东西):

int main()
{
    Move<OverVoid> m1;
    Move<Meta> m2;
    Move<int> m3;
    return 0;
}

输出:

错误:'struct std::enable_if' 中没有名为 'type' 的类型

typedef typename std::enable_if::value, _Ty>::type 类型;

Live sample.

这是一个非常好的解决方案,因为它不能被欺骗 - 总是可以手动指定 Move 的附加模板参数(除非 OverVoid 和 Meta 不暴露给客户端)。

【讨论】:

    【解决方案2】:

    您可以隐藏非 OverVoid 类型的类的模板定义

    template<typename _Ty, 
             class = typename std::enable_if<std::is_base_of<OverVoid, _Ty>::value>::type>
    class Move{
    
    };
    

    然后在尝试编译非 OverVoid 类型的类时会出错。

    int main() {
    
      Move<Meta> a;
      Move<OverVoid> b;
      Move<Physical> c;
      // your code goes here
      return 0;
    }
    

    错误:

    prog.cpp: In function 'int main()':
    prog.cpp:29:15: error: no type named 'type' in 'struct std::enable_if<false,    void>'
    Move<Physical> c;
    

    【讨论】:

    • 感谢您的帮助,但是如果 _Ty 实际上是 Meta* 怎么办,它不起作用,那么有解决方法吗?
    • 可以使用std::remove_pointer&lt;_Ty&gt;来移除指针,获取基类型。
    • class = typename std::enable_if&lt;std::is_base_of&lt;OverVoid, std::remove_pointer&lt;_Ty&gt;::type&gt;::value&gt;::type&gt;
    【解决方案3】:

    最简单的就是static_assert:

    template<typename _Ty>
    class Move {
        static_assert(std::is_base_of<OverVoid, _Ty>::value, 
                      "_Ty must inherit from OverVoid.");
    };
    

    请注意,这允许OverVoid 成为私有或不可访问的基础。如果你想要求它是一个公共基础,你可以改为要求:

        static_assert(std::is_convertible<_Ty*, OverVoid*>::value, 
                      "_Ty must inherit publicly from OverVoid.");
    

    【讨论】:

    • 您好,我尝试了您的方法,但它需要带有 msvc++ 的 /EHsc 标志,由于开发问题,我无法使用该标志,但无论如何感谢 :)
    猜你喜欢
    • 1970-01-01
    • 2022-01-11
    • 2016-07-23
    • 1970-01-01
    • 2011-12-20
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多