C++ template specialization without default function
我有以下代码可以很好地编译和工作:
1 2 3 4 5 6 7 8 | template<typename T> T GetGlobal(const char *name); template<> int GetGlobal<int>(const char *name); template<> double GetGlobal<double>(const char *name); |
不过,我想删除"默认"功能。也就是说,我想对getglobal进行所有调用,其中"t"不是int,也不是double。
例如,getglobal
我试图删除默认函数,但正如我想象的那样,我收到了很多错误。那么有没有一种方法可以"禁用"它并只允许调用函数的专门版本?
谢谢!
要获取编译时错误,请将其实现为:
1 2 3 | template<typename T> T GetGlobal(const char *name) { T::unimplemented_function; } // `unimplemented_function` identifier should be undefined |
如果使用Boost,可以使其更优雅:
1 2 | template<typename T> T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); } |
C++标准保证不存在大小等于0的这样的类型,因此将获得编译时错误。
正如SBI在他的评论中建议的,最后一个可以简化为:
1 2 | template<typename T> T GetGlobal(const char *name) { char X[!sizeof(T)]; } |
我更喜欢第一个解决方案,因为它给出的错误信息(至少在VisualC++中)比其他的更清楚。
虽然这是一个陈旧过时的问题,但值得注意的是,
1 2 3 4 5 | template<typename T> T GetGlobal(const char *name) = delete; template<> int GetGlobal<int>(const char *name); |
更新
这不会在
以下解决方法将适合这个问题(使用
1 2 3 4 5 6 7 | template<typename T> T GetGlobal(const char *name) { static_assert(sizeof(T) == 0,"Only specializations of GetGlobal can be used"); } template<> int GetGlobal<int>(const char *name); |
更新
Visual Studio 15.9有相同的错误。使用以前的解决方法。
如果不实现它,至少会得到一个链接器错误。如果需要编译时错误,可以使用类模板执行此操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | template<typename T> struct GlobalGetter; template<> struct GlobalGetter<int> { static int GetGlobal(const char *name); }; template<> struct GlobalGetter<double> { static double GetGlobal(const char *name); }; template<typename T> T GetGlobal(const char *name) { return GlobalGetter<T>::GetGlobal(name); } |
我建议不要实际提供一个实现,只提供方法的一个简单声明。
另一种选择是使用编译时断言。Boost有很多这样的野兽。
1 2 3 | namespace mpl = boost::mpl; BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>, boost::same_type<T, int> >)); |
还有它的消息版本对应物,这将有所帮助。
以下是使用Boost的替代技术:
将typedef声明为依赖名称
这是因为名称查找不仅在"t"被替换时发生。这是kirill给出的示例的类似(但合法)版本
1 2 3 4 | template <typename T> T GetGlobal (const char * name) { typedef typename T::DONT CALL_THIS_FUNCTION; } |
使用不完整的返回类型
这项技术不适用于专门化,但适用于重载。其思想是,声明返回不完整类型但不调用该类型的函数是合法的:
1 2 | template <typename T> class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name); |