C++ C++;没有默认函数的模板专门化

C++ C++;没有默认函数的模板专门化,c++,templates,specialization,C++,Templates,Specialization,我有以下代码可以编译并运行良好: template<typename T> T GetGlobal(const char *name); template<> int GetGlobal<int>(const char *name); template<> double GetGlobal<double>(const char *name); 模板 T GetGlobal(常量字符*名称); 模板 int GetGlobal(常量

我有以下代码可以编译并运行良好:

template<typename T>
T GetGlobal(const char *name);

template<>
int GetGlobal<int>(const char *name);

template<>
double GetGlobal<double>(const char *name);
模板
T GetGlobal(常量字符*名称);
模板
int GetGlobal(常量字符*名称);
模板
双GetGlobal(常量字符*名称);
但是,我想删除“default”函数。也就是说,我想对GetGlobal进行所有调用,其中“t”不是int或double,而是一个错误

例如,GetGlobal()应该是编译时错误

我试图删除默认函数,但正如我想象的那样,我收到了很多错误。。那么,有没有一种方法可以“禁用”它并只允许调用函数的专用版本呢


谢谢

要获取编译时错误,请将其实现为:

template<typename T>
T GetGlobal(const char *name) { T::unimplemented_function; }
// `unimplemented_function` identifier should be undefined
模板
T GetGlobal(const char*name){T::未实现的函数;}
//`unimplemented_function`标识符应未定义
如果使用Boost,则可以使其更加优雅:

template<typename T>
T GetGlobal(const char *name) { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
模板
T GetGlobal(const char*name){BOOST_STATIC_ASSERT(sizeof(T)==0)}
C++标准保证没有sizeof等于0的类型,因此会出现编译时错误

正如他在评论中所建议的那样,最后一项可以缩减为:

template<typename T>
T GetGlobal(const char *name) { char X[!sizeof(T)]; }
模板
T GetGlobal(const char*name){char X[!sizeof(T)];}

我更喜欢第一种解决方案,因为它比其他解决方案提供了更清晰的错误消息(至少在Visual C++中是如此)。

我建议不要实际提供实现,只提供方法的简单声明

另一个选项是使用编译时断言。Boost有很多这样的野兽

namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
                            boost::same_type<T, int> >));
namespace-mpl=boost::mpl;
BOOST\u MPL\u ASSERT((MPL::或);

还有它的消息版本对应项,这会有所帮助。

如果不实现它,至少会出现链接器错误。如果需要编译时错误,可以使用类模板执行此操作:

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);
}
模板
结构全局代数;
模板
结构全局代数{
静态int GetGlobal(常量字符*名称);
};
模板
结构全局代数{
静态双GetGlobal(常量字符*名称);
};
模板
T GetGlobal(常量字符*名称)
{
返回GlobalGetter::GetGlobal(名称);
}

以下是使用boost的替代技术:

将typedef声明为从属名称

这是因为只有在“T”被替换时,才会对“not”进行名称查找。这与下面给出的示例类似(但合法)

模板
T GetGlobal(常量字符*名称){
typedef typename T::不要调用此函数;
}
使用不完整的返回类型

这种技术不适用于专门化,但适用于重载。其思想是,声明返回不完整类型的函数是合法的,但不调用它:

template <typename T>
class DONT_CALL_THIS_FUNCTION GetGlobal (const char * name);
模板
类不调用此函数GetGlobal(const char*name);

尽管这是一个古老而过时的问题,但值得注意的是,
C++11
使用删除的函数解决了这个问题:

template<typename T>
T GetGlobal(const char *name) = delete;

template<>
int GetGlobal<int>(const char *name);

更新


VisualStudio15.9也有同样的错误。使用前面的解决方法。

为了使第一个案例在编译时失败,Koper需要一个未声明的函数,而不是未定义的函数。要编译它,唯一的方法就是使它依赖于
T
。类似于
T::一些\u肯定是\u未声明的东西\u可能会这样做。(第二个可能可以用
char dummy[!sizeof(T)];
模拟)使用
unimplemented_函数
比使用
T::unimplemented_函数
@Kirill提供更清晰的错误消息(至少在Visual C++中是如此):使用
unimplemented_函数
在执行两阶段查找的编译器中不起作用。(目前,VC不这样做。)这样的编译器不会编译模板定义,即使它从未实例化。-1:SBI是正确的。查找标识符时,由于它不是带有从属参数的功能调用(即ADL调用),因此它将是一个错误。请修正这个例子——并收回你的观点!:)类似这样的
模板结构没有定义:mpl::false{};模板T GetGlobal(char const*name){BOOST_MPL_ASSERT((未定义))}
将给出一些不错的错误:。知道模板函数前向声明不会产生编译器错误的原因吗,而模板类转发声明确实如此?如果您的专门化比“int”和“double”多得多,那么编写的内容就太多了。什么是
GlobalGetter(name)
?建造师?在
GlobalGetter
GlobalGetter
@xtofl:中没有带单参数的构造函数,因为编译函数调用只需要函数模板声明。(而对于类,您需要定义。)@Kiril:您没有编写函数模板专门化,而是为只包含一个stat函数的类模板编写专门化。是的,需要再敲几下键盘才能打字,但没那么糟。但是,您的第二个解决方案(使用
STATIC\u ASSRT
的解决方案)也是我喜欢的。这是最好的解决方案,谢谢!它可能也与此相关:llvm 5.0和3.9已经修复了此错误。
template<typename T>
T GetGlobal(const char *name) = delete;

template<>
int GetGlobal<int>(const char *name);
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);