问题描述
有时在使用C ++模板进行编码时,您需要防止用户实例化特定的专业化或一组专业化,因为结果是荒谬的.因此,您可以定义(特定或部分)专业化,其定义(如果实例化)会导致编译器错误.目的是,如果用户"滥用"模板,请在标题文件中的注释旁边引起编译器错误,以解释不执行的操作,而不是让编译器自己提出一些混乱的错误消息设备,或者允许可疑代码编译.
示例:
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; };
有多种方法可以做到这一点(取决于您的专业化是类或功能的完整还是部分专业化).但是使用的语法必须(?)取决于模板参数,否则编译器首先解析故意错误定义时会抱怨.上面的示例有一个漏洞,即有人可以固执地定义intentional_error嵌套类型或typedef(尽管我说他们应该遇到任何问题,因此他们应该遇到任何问题).但是,如果您使用的技巧太花哨了,那么您可能会收到难以理解的和/或误导性编译器错误消息,这大多会破坏目的.
是否有更好的直接方法禁止模板实例化?
我知道,在C ++ 0x中,模板概念和已删除的函数声明将为此类事情提供更好的控制,但是我正在寻找有效C ++ 03的答案.
推荐答案
您可以省略定义.
template <typename T> struct MyClassTemplate<T*>;
您也可以从非定义的专业化
衍生template <typename T> struct invalid; template <typename T> struct MyClassTemplate<T*> : invalid<T> { };
请注意,声明类或功能的明确专业将永远不会取决于模板参数.因此,取决于模板参数的类似内容无论如何都无法正常工作.在这种情况下,声明非定义的显式专业化应该足够
template<> struct MyClassTemplate<int*>;
其他推荐答案
对我来说,这听起来像 static_assert 来自C ++ 0x或 BOOST_STATIC_ASSERT . static_assert "> static_assert 功能具有优势您可以传递自定义错误消息,以使错误的原因更为明确.
两种方式都为您提供了在某些自定义定义的编译时间条件下过早结束编译过程的机会.
使用static_assert:
template <typename T> struct MyClassTemplate<T*> { static_assert(always_false<T>::value, "Do not use MyClassTemplate with a pointer type!"); };
使用boost_static_assert
template <typename T> struct MyClassTemplate<T*> { // Do not use MyClassTemplate with a pointer type! BOOST_STATIC_ASSERT(always_false<T>::value); };
总是false看起来像这样:
template< typename T > struct always_false { enum { value = false }; };
hth
编辑:修复了使它们真正起作用的示例;-)感谢Gman!
其他推荐答案
如果您不想使用库,则此构造非常可靠(大致是Boost在内部做的):
template <typename T> void must_be_specialized(T const&) { enum dummy { d = (sizeof(struct must_be_specialized_for_this_type) == sizeof(T)) }; }
您可以在专业化中放入类似的东西,以禁止使用该类型的模板实例化.我个人不会担心must_be_specialized_for_this_type从某个地方获得定义,但是您可以使用前向声明将其松化在私人名称空间中.
.问题描述
Sometimes when coding with C++ templates, you want to prevent users from instantiating a specific specialization or set of specializations, because the result would be nonsensical. So you can define a (specific or partial) specialization whose definition, if instantiated, would cause a compiler error. The goal would be, if a user "misuses" the template, to cause a compiler error right next to a comment in your header file explaining what not to do, rather than leaving the compiler to come up with some confusing error message by its own devices, or maybe allowing the questionable code to compile.
Example:
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; };
There are a number of ways to do this (depending on whether your specialization is a complete or partial specialization of a class or function). But the syntax used must (?) depend on a template parameter, or else the compiler will complain when it first parses the intentional-error definition. The example above has a hole in that somebody could stubbornly define an intentional_error nested type or member typedef (though I'd say they would then deserve whatever problems come up as a result). But if you use a trick too fancy, you're likely to get an indecipherable and/or misleading compiler error message, which mostly defeats the purpose.
Are there better straightforward ways to disallow template instantiations?
I'm aware that in C++0x, template Concepts and deleted function declarations will provide much better control over this sort of thing, but I'm looking for answers that are valid C++03.
推荐答案
You could just omit defining it.
template <typename T> struct MyClassTemplate<T*>;
You could also derive from a non-defined specialization
template <typename T> struct invalid; template <typename T> struct MyClassTemplate<T*> : invalid<T> { };
Note that explicit specializations that declare classes or functions will never depend on template parameters. So, stuff like this that depend on template parameters can't work anyway. In that case, declaring a non-defined explicit specialization should be sufficient
template<> struct MyClassTemplate<int*>;
其他推荐答案
For me this sounds like a typical case for static_assert from C++0x or BOOST_STATIC_ASSERT. The static_assert functionality has the advantage that you can pass a custom error message so that the reason for the error is more clear.
Both ways are giving you the opportunity to prematurely end the compilation process under some custom defined compile time condition.
with static_assert:
template <typename T> struct MyClassTemplate<T*> { static_assert(always_false<T>::value, "Do not use MyClassTemplate with a pointer type!"); };
with BOOST_STATIC_ASSERT
template <typename T> struct MyClassTemplate<T*> { // Do not use MyClassTemplate with a pointer type! BOOST_STATIC_ASSERT(always_false<T>::value); };
Always false would look something like this:
template< typename T > struct always_false { enum { value = false }; };
HTH
Edit: Fixed the examples to make them actually work ;-) Thanks to GMan!
其他推荐答案
If you don't want to use a library, this construct is pretty reliable (it's roughly what Boost does internally):
template <typename T> void must_be_specialized(T const&) { enum dummy { d = (sizeof(struct must_be_specialized_for_this_type) == sizeof(T)) }; }
You can put something analogous in a specialization to disallow instantiation of the template with that type. I wouldn't, personally, worry about must_be_specialized_for_this_type gaining a definition from somewhere, but you could use a forward declaration to squirrel it away in a private namespace if you really wanted.