没有默认功能的C ++模板专业化

时间:2009-10-27 08:25:12

标签: 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);

但是我想删除“默认”功能。也就是说,我想打电话给GetGlobal&lt; t&gt;其中't'不是int或double错误。

例如,GetGlobal&lt; char&gt;()应该是编译时错误。

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

谢谢!

5 个答案:

答案 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);