如何将模板类限制为某些内置类型?

时间:2013-06-07 05:18:44

标签: c++ templates visual-studio-2012 c++11 static-assert

这个问题已经讨论了几次,但我发现的所有解决方案要么不起作用,要么基于boost的静态断言。我的问题很简单。我有一个类,我只想允许真正的类型(double和float)。如果我尝试使用float或double以外的类型实例化类,我想要一个编译时错误。我正在使用Visual C ++ 11.这是我尝试过的:

template <typename RealType>
class A
{
  // Warning C4346
  static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value);
}


template <typename RealType>
class A
{
  // Error C2062: type 'unknown' unexpected
  static_assert(decltype(RealType) == double || decltype(RealType) == float);
}

有什么想法吗?提前谢谢!

3 个答案:

答案 0 :(得分:29)

在您的第一个示例中,static_assert应该采用第二个参数,该参数将是字符串文字,否则它被视为失败(编辑:删除第二个参数是合法自C ++ 17)。而这第二个论点不能违约。

你的第二个例子是不正确的,原因如下:

  • decltype旨在用于表达式,而不是用于类型。
  • 您无法将类型与==进行比较,正确的方法是首次尝试使用std::is_same时尝试的方法。

因此,正确的做法是:

#include <type_traits>

template <typename RealType>
class A
{
  static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value,
                "some meaningful error message");
};

此外,我打赌你试图将模板限制为浮点值。为此,您可以使用特征std::is_floating_point

#include <type_traits>

template <typename RealType>
class A
{
  static_assert(std::is_floating_point<RealType>::value,
                "class A can only be instantiated with floating point types");
};

作为奖励,请this online example

答案 1 :(得分:21)

我见过的一个解决方案是在类型别名中使用std::enable_if。类似的东西:

using value_type = typename std::enable_if<
                    std::is_same<float, RealType>::value ||
                    std::is_same<double, RealType>::value,
                    RealType
                >::type;

value_type仅在RealType完全floatdouble时才存在。否则,类型未定义,编译失败。

但是,我警告说对类型过于严格。模板和它们一样强大,部分原因是它们所做的鸭子打字意味着任何可以按照你想要的方式使用的类型都可以使用。禁用类型以禁用类型通常不会给你带来太大的好处,并且会使事情变得不那么灵活。例如,您将无法使用具有更高精度的类型,如大十进制类型。

答案 2 :(得分:5)

这样它还允许对各种类型进行专业化:

template<typename T, typename Enable = void>
class A {
/// Maybe no code here or static_assert(false, "nice message");
};

/// This specialization is only enabled for double or float.
template<typename T>
class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> {

};