【问题标题】:How do I restrict a template class to certain built-in types?如何将模板类限制为某些内置类型?
【发布时间】:2013-06-03 07:48:00
【问题描述】:

这个问题已经讨论过几次,但我发现的所有解决方案要么不起作用,要么基于 boost 的静态断言。我的问题很简单。我有一堂课,我只想允许真正的类型(双精度和浮点数)。如果我尝试使用浮点或双精度以外的类型实例化类,我想要一个编译时错误。我正在使用 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);
}

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

【问题讨论】:

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


【解决方案1】:

在您的第一个示例中,static_assert 应采用第二个参数,该参数将是字符串文字,否则将被视为失败(edit: 自 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

【讨论】:

    【解决方案2】:

    我见过的一个解决方案是在类型别名中使用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 时才存在。否则,类型未定义,编译失败。

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

    【讨论】:

    • 那,如果你只需要两个特化,好的旧的 OO 和运行时多态性可能是一个更好的主意(至少值得考虑)。
    • SFINAE 非常好,当您以后想创建更多的模板专业化时:) 但是,如果 zhe 确定永远不会有任何其他专业化,static_assert 允许显示有意义的错误消息(因为 SFINAE那些经常伤害我的眼睛)。
    【解决方案3】:

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

    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> {
    
    };
    

    【讨论】:

    • static_assert(false, "nice message"); 程序格式错误,无需诊断。请参阅stackoverflow.com/questions/30078818/… 那里的问题起初看起来更复杂,但下划线原因与您的示例一样简单。
    【解决方案4】:

    C++20 概念用法

    https://en.cppreference.com/w/cpp/language/constraints cppreference 给出了与我在C++ templates that accept only certain types 中提到的相似的继承示例,据此猜测,我认为特定类的语法将是:

    template <class T, class Class1, class Class2>
    concept Derived = std::is_same<U, Class1>::value || std::is_same<U, Class2>::value;
    
    template<Derived<MyClass1, MyClass2> T>
    void f(T);
    

    但由于编译器支持,我还无法对此进行测试,如其他答案中所述。

    【讨论】:

      猜你喜欢
      • 2019-10-23
      • 1970-01-01
      • 2015-11-22
      • 2022-11-12
      • 1970-01-01
      • 2014-08-20
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      相关资源
      最近更新 更多