38

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

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

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

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

但是我想删除“默认”功能。也就是说,我想对 GetGlobal<t> 进行所有调用,其中 't' 不是 int 或 double 错误。

例如,GetGlobal<char>() 应该是编译时错误。

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

谢谢!

4

5 回答 5

35

虽然这是一个古老而过时的问题,但可能值得注意的是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 有同样的错误。使用以前的解决方法。

于 2016-06-02T13:20:20.613 回答
32

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

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++ 标准保证不存在 sizeof 等于 0 的此类类型,因此您将收到编译时错误。

正如sbi在他的评论中建议的那样,最后一个可以简化为:

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

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

于 2009-10-27T08:28:57.480 回答
6

如果你不实现它,你至少会得到一个链接器错误。如果你想要一个编译时错误,你可以使用类模板来做到这一点:

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);
}
于 2009-10-27T08:39:56.367 回答
3

我建议不要实际提供实现,而只是简单地声明该方法。

另一种选择是使用编译时断言。Boost有许多这样的野兽。

namespace mpl = boost::mpl;
BOOST_MPL_ASSERT((mpl::or_< boost::same_type<T, double>,
                            boost::same_type<T, int> >));

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

于 2009-10-27T08:37:21.200 回答
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);
于 2009-10-27T12:20:15.517 回答