没有默认功能的C ++模板专业化
-
06-07-2019 - |
题
我有以下编译并运行良好的代码:
template<typename T>
T GetGlobal(const char *name);
template<>
int GetGlobal<int>(const char *name);
template<>
double GetGlobal<double>(const char *name);
但是我想删除<!> quot; default <!> quot;功能。也就是说,我想对GetGlobal进行所有调用<!> lt; t <!> gt;其中't'不是int或double错误。
例如,GetGlobal <!> lt; char <!> gt;()应该是编译时错误。
我试图删除默认函数,但是,正如我想象的那样,我收到了很多错误..那么有没有办法<!> quot; disable <!> quot;它并且只允许调用该函数的专用版本?
谢谢!
解决方案
要获得编译时错误,请将其实现为:
template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined
如果你使用Boost,你可以使它更优雅:
template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
C ++ Standard保证不存在sizeof等于0的类型,因此您将收到编译时错误。
正如 sbi 在他的评论中建议的那样,最后可以缩减为:
template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }
我更喜欢第一种解决方案,因为它提供了比其他解决方案更清晰的错误消息(至少在Visual C ++中)。
其他提示
虽然这是一个陈旧且过时的问题,但值得注意的是C++11
使用已删除的函数解决了这个问题:
template<typename T>
T GetGlobal(const char *name) = delete;
template<>
int GetGlobal<int>(const char *name);
<强>更新强>
这不会在MacOS llvm 8
下编译。
这是由于仍然悬挂4年的缺陷(参见此错误报告) )。
以下解决方法适合该问题(使用static_assert
构造)。
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有相同的bug。使用以前的解决方法。
如果你没有实现它,你至少会得到一个链接器错误。如果您想要编译时错误,可以使用类模板执行此操作:
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有很多这样的野兽。
namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
boost::same_type<T, int> >));
还有它的消息版本副本,这将有所帮助。
以下是使用boost的替代技术:
将typedef声明为从属名称
这是有效的,因为DONT的名称查找仅在替换'T'时发生。这是 Kirill <给出的类似(但合法)的示例版本/ A>
template <typename T>
T GetGlobal (const char * name) {
typedef typename T::DONT CALL_THIS_FUNCTION;
}
使用不完整的返回类型
此技术不适用于专业化,但它适用于重载。这个想法是声明一个函数返回一个不完整的类型,而不是调用它是合法的:
template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);