我有以下编译并运行良好的代码:
template<typename T>
T GetGlobal(const char *name);
template<>
int GetGlobal<int>(const char *name);
template<>
double GetGlobal<double>(const char *name);
但是我想删除“默认”功能。也就是说,我想打电话给GetGlobal&lt; t&gt;其中't'不是int或double错误。
例如,GetGlobal&lt; char&gt;()应该是编译时错误。
我试图删除默认函数,但是,正如我想象的那样,我收到了很多错误。那么有没有办法“禁用”它并且只允许调用函数的专用版本?
谢谢!
答案 0 :(得分:25)
要获得编译时错误,请将其实现为:
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 ++中)。
答案 1 :(得分:14)
虽然这是一个陈旧且过时的问题,但值得注意的是C++11
已使用已删除的函数解决了此问题:
template<typename T>
T GetGlobal(const char *name) = delete;
template<>
int GetGlobal<int>(const char *name);
<强>更新强>
这不会在MacOS llvm 8
下编译。
这是由于一个仍然悬挂4年的缺陷(见this bug report)。
以下解决方法适合该问题(使用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。使用以前的解决方法。
答案 2 :(得分:5)
如果你没有实现它,你至少会得到一个链接器错误。如果您想要编译时错误,可以使用类模板执行此操作:
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);
}
答案 3 :(得分:3)
我建议不要实际提供一个实现,只是声明该方法。
另一种选择是使用编译时断言。 Boost有很多这样的野兽。
namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
boost::same_type<T, int> >));
还有它的消息版本副本,这将有所帮助。
答案 4 :(得分:2)
以下是使用boost的替代技术:
将typedef声明为从属名称
这是有效的,因为DONT的名称查找仅在替换'T'时发生。这是Kirill
给出的示例的类似(但合法)版本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);