Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/161.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在模板实例化时故意导致编译时错误 有时候,当用C++模板编码时,您希望防止用户实例化特定的专门化或专门化的集合,因为结果是荒谬的。因此,您可以定义(特定的或部分的)专门化,其定义如果实例化,将导致编译器错误。目标是,如果用户“误用”模板,就在头文件中解释不应该做什么的注释旁边导致编译器错误,而不是让编译器自己的设备产生一些令人困惑的错误消息,或者允许有问题的代码编译_C++_Design Patterns_Templates - Fatal编程技术网

如何在模板实例化时故意导致编译时错误 有时候,当用C++模板编码时,您希望防止用户实例化特定的专门化或专门化的集合,因为结果是荒谬的。因此,您可以定义(特定的或部分的)专门化,其定义如果实例化,将导致编译器错误。目标是,如果用户“误用”模板,就在头文件中解释不应该做什么的注释旁边导致编译器错误,而不是让编译器自己的设备产生一些令人困惑的错误消息,或者允许有问题的代码编译

如何在模板实例化时故意导致编译时错误 有时候,当用C++模板编码时,您希望防止用户实例化特定的专门化或专门化的集合,因为结果是荒谬的。因此,您可以定义(特定的或部分的)专门化,其定义如果实例化,将导致编译器错误。目标是,如果用户“误用”模板,就在头文件中解释不应该做什么的注释旁边导致编译器错误,而不是让编译器自己的设备产生一些令人困惑的错误消息,或者允许有问题的代码编译,c++,design-patterns,templates,C++,Design Patterns,Templates,例如: template <typename T> struct MyClassTemplate { // ... }; template <typename T> struct MyClassTemplate<T*> { // Do not use MyClassTemplate with a pointer type! typedef typename T::intentional_error err; }; 模板结构MyClassTemp

例如:

template <typename T> struct MyClassTemplate {
  // ...
};

template <typename T> struct MyClassTemplate<T*> {
  // Do not use MyClassTemplate with a pointer type!
  typedef typename T::intentional_error err;
};
模板结构MyClassTemplate{
// ...
};
模板结构MyClassTemplate{
//不要将MyClassTemplate与指针类型一起使用!
typedef typename T::故意_错误错误;
};
有很多方法可以做到这一点(取决于您的专门化是类或函数的完全专门化还是部分专门化)。但是所使用的语法必须(?)依赖于模板参数,否则编译器在第一次解析故意错误定义时会抱怨。上面的例子有一个漏洞,有人可能会顽固地定义一个
故意的_错误
嵌套类型或成员typedef(尽管我认为他们应该得到由此产生的任何问题)。但是如果你使用的技巧太花哨了,你很可能会得到一条无法辨认和/或误导的编译器错误消息,而这往往会破坏你的目的


是否有更好的直接方法来禁止模板实例化


我知道在C++0x中,模板概念和已删除的函数声明可以更好地控制这类事情,但我正在寻找有效的C++03答案。

概念已从“0x”中删除。您可以使用库,如。

boost::enable\u如果您可以省略对它的定义

template <typename T> struct MyClassTemplate<T*>;
模板结构MyClassTemplate;
您还可以从未定义的专门化派生

template <typename T> struct invalid;
template <typename T> struct MyClassTemplate<T*> : invalid<T> { };
模板结构无效;
模板结构MyClassTemplate:无效{};
请注意,声明类或函数的显式专门化永远不会依赖于模板参数。所以,像这样依赖于模板参数的东西无论如何都不能工作。在这种情况下,声明一个未定义的显式专门化就足够了

template<> struct MyClassTemplate<int*>;
模板结构MyClassTemplate;

如果您不想使用库,此构造非常可靠(它大致与Boost内部的功能相同):

模板
void必须是专用的(T常量&)
{
枚举伪{d=(sizeof(对于此类型,结构必须是专用的)
==sizeof(T))};
}

您可以在专门化中添加类似的内容,以禁止使用该类型实例化模板。就我个人而言,我不会担心这种类型的
必须是专门的
从某处获取定义,但是如果您真的愿意,您可以使用前向声明将其存储在私有名称空间中。

对我来说,这听起来像是来自C++0x或的典型情况。该功能的优点是,您可以传递自定义错误消息,以便更清楚地了解错误原因

这两种方法都让您有机会在某些自定义的编译时条件下提前结束编译过程

使用静态_断言:

template <typename T> struct MyClassTemplate<T*> {
    static_assert(always_false<T>::value, "Do not use MyClassTemplate with a pointer type!");
};
模板结构MyClassTemplate{
静态_断言(总是_false::value,“不要将MyClassTemplate与指针类型一起使用!”);
};
使用BOOST\u STATIC\u ASSERT

template <typename T> struct MyClassTemplate<T*> {
    // Do not use MyClassTemplate with a pointer type!
    BOOST_STATIC_ASSERT(always_false<T>::value);
};
模板结构MyClassTemplate{
//不要将MyClassTemplate与指针类型一起使用!
BOOST\u STATIC\u ASSERT(总是\u false::value);
};
“始终为false”看起来像这样:

template< typename T >
struct always_false { 
    enum { value = false };  
};
模板
结构总是_false{
枚举{value=false};
};

编辑:修复了示例以使其实际工作;-)多亏了格曼

“有没有更好的直接方法来禁止模板实例化?”没有比您已经确定的更好的方法了。我非常肯定C++保护机制可以保护你免受意外伤害,而不是恶意伤害。如果有人定义专业或课程来破坏你的预期用途,我会认为是恶意的。也许你可以在他们每次这样做的时候打他们的后脑勺

我个人更喜欢将检查放入现有的模板中,这些模板只用于描述检查。这允许有趣的继承和模板组合

template <class T>
class not_with_pointer_t { };

template <class T>
class not_with_pointer_t<T*>;

template <class T>
class some_class_t : public not_with_pointer_t<T> { };

template <class T, template <class U> class base_t>
class another_class_t : public base_t<T> { };

typedef some_class_t<int> a_t; // ok
typedef some_class_t<void*> b_t; // error if instantiated
typedef another_class_t<void*, not_with_pointer_t> c_t; // error if instantiated

template <class T> class unrestricted_t { };
typedef another_class_t<void*, unrestricted_t> d_t; // ok
模板
类not_与_指针_t{};
模板
使用指针\u t初始化not\u;
模板
类some_class_t:public not_与_pointer_t{};
模板
类另一类:公共基{};
键入def某些类/好啊
键入def某些类/实例化时出错
键入def另一个_class_t c_t;//实例化时出错
模板类不受限制{};
键入定义另一个\u类\u t d\u t;//好啊

其中一些会在链接时而不是编译时出错,不是吗?哦,没错,因为要实例化类模板,必须有完整的类声明。我想到的是函数模板。@Johannes:嗨,我不知道你是怎么做到的。你能解释一下这是怎么回事吗?模板结构无效;模板结构MyClassTemplate:无效{};一个变态的程序员可能会为您未定义的模板或专门化提供定义。当然,这一点是为了防止偶然的例证,最后你永远无法完全保护任何一个不正常的程序员。@阿斯克罗夫:正如一句谚语所说,C++可以保护你自己免受Murphy(有时丑陋的把戏)的保护,但是你不能保护自己不受马基雅维利的攻击。如果两种类型的大小相同,会发生什么情况?还有e的部分是什么
template <class T>
class not_with_pointer_t { };

template <class T>
class not_with_pointer_t<T*>;

template <class T>
class some_class_t : public not_with_pointer_t<T> { };

template <class T, template <class U> class base_t>
class another_class_t : public base_t<T> { };

typedef some_class_t<int> a_t; // ok
typedef some_class_t<void*> b_t; // error if instantiated
typedef another_class_t<void*, not_with_pointer_t> c_t; // error if instantiated

template <class T> class unrestricted_t { };
typedef another_class_t<void*, unrestricted_t> d_t; // ok