创建仅限专业化功能模板的最佳方法是什么?

vol*_*evo 9 c++ templates boost template-specialization

有没有更好的方法来做到以下几点?

#include <iostream>

template <typename T>
T Bar();

template <>
int Bar<int>() { return 3; }

// Potentially other specialisations

int main()
{
    std::cout << Bar<int>() << std::endl; // This should work
    std::cout << Bar<float>() << std::endl; // This should fail
}
Run Code Online (Sandbox Code Playgroud)

该解决方案的问题在于它(可理解地)链接时间与"未定义的浮点引用Bar<float>()"等失败.这可能会让其他开发人员感到困惑,因为他们可能怀疑实现文件没有被链接.

我知道另一种可能的解决方案:

template <typename T>
T Bar() { BOOST_STATIC_ASSERT(sizeof(T) == 0); }
Run Code Online (Sandbox Code Playgroud)

这会在Bar<float>()请求时导致编译器错误,正是我想要的.但是,我担心技术上编译器可能会拒绝这一点,就像gcc拒绝一样,BOOST_STATIC_ASSERT(false)因为它知道无论模板参数如何都会失败,因为sizeof(T)永远不会为零.

总之,我想知道是否:

  1. 还有另一种方法可以做到这一点.
  2. 我错了,BOOST_STATIC_ASSERT(sizeof(T))实际上没有实例化也不会失败.
  3. 唯一的方法是让它成为上面的链接器错误.

Pub*_*bby 6

这可能有效:

template <typename T>
T Bar() {
  T::ERROR_invalid_template_argument_;
}

template <>
int Bar<int>() { return 3; }
Run Code Online (Sandbox Code Playgroud)

如果您害怕使用0,您也可以使用最大尺寸:

  static_assert(sizeof(T) == -1, "No specialization");
Run Code Online (Sandbox Code Playgroud)

  • @ Mozza314:因为`sizeof`的类型是`std :: size_t`(无符号整数类型),-1将被提升为无符号类型(使用模运算,保证最大值).也就是说,只需使用零.在某些时候,你必须相信编译器正在做正确的事情. (2认同)

GMa*_*ckG 4

BOOST_STATIC_ASSERT(sizeof(T) == 0);在实例化模板之前不允许失败,所以我只会这样做。你是对的,BOOST_STATIC_ASSERT(false);每次都会触发。

\n\n
\n\n

其原因与两阶段名称查找有关。这本质上是这样的:编译模板时,它会被编译两次。编译器第一次看到模板时,它会编译除依赖于模板参数的表达式之外的所有内容,一旦知道模板参数,就会进行第二次编译,从而完全编译实例化。

\n\n

这就是为什么BOOST_STATIC_ASSERT(false);总是失败的原因:这里没有任何依赖项,并且断言会立即处理,就好像该函数根本不是模板一样。(请注意,MSVC 没有实现两阶段查找,因此在实例化时会错误地失败。)相反,因为T是依赖的 (\xc2\xa714.6.2.1),所以BOOST_STATIC_ASSERT(sizeof(T) == 0);是依赖的,并且不允许在检查之前进行检查模板被实例化。(在上面它总是会失败。)

\n\n

如果编译器试图深思熟虑并提前失败,那么它将是不合格的。你应该能够依赖这个东西。也就是说,如果恐惧战胜了你,那么真正让它等待是微不足道的:

\n\n
BOOST_STATIC_ASSERT(sizeof(typename T::please_use_specializations) == 0);\n
Run Code Online (Sandbox Code Playgroud)\n\n

这既保证会失败,又不可能让编译器提前正确地“智能”失败。

\n