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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16976720/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 20:47:39  来源:igfitidea点击:

How do I restrict a template class to certain built-in types?

c++templatesvisual-studio-2012c++11static-assert

提问by quant

This issue has been discussed a few times but all the solutions I have found either didn't work or were based on boost's static assert. My problem is simple. I have a class, and I only want to allow real types (double and float). I want a compile-time error if I try to instantiate the class with a type other than float or double. I am using Visual C++ 11. Here is what I have tried:

这个问题已经讨论过几次,但我发现的所有解决方案要么不起作用,要么基于 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);
}

Any ideas? Thanks in advance!

有任何想法吗?提前致谢!

采纳答案by cHao

One solution I've seen is to use std::enable_ifin a type alias. Something like:

我见过的一种解决方案是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_typeonly exists if RealTypeis exactly floator double. Otherwise, the type is undefined and compilation fails.

value_type仅当RealTypefloat或时才存在double。否则,类型未定义且编译失败。

I'd warn about being too strict with types, though. Templates are as powerful as they are partly because the duck typing they do means that any type that can be used the way you want to use it, will work. Disallowing types for the sake of disallowing types generally doesn't gain you much, and can make things less flexible than they could be. For example, you wouldn't be able to use a type with more precision, like a big-decimal type.

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

回答by Morwenn

In your first example, static_assertshould take a second parameter which would be a string literal, otherwise it's deemed to fail (edit:dropping the the second parameter is legal since C++17). And this second argument cannot be defaulted.

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

Your second example is incorrect for several reasons:

由于以下几个原因,您的第二个示例不正确:

  • decltypeis meant to be used on an expression, not on a type.
  • You simply cannot compare types with ==, the correct way to do this is what you try in your first attempt with std::is_same.
  • decltype旨在用于表达式,而不是类型。
  • 您根本无法将类型与 进行比较==,正确的方法是您在第一次尝试时尝试使用std::is_same.

So, the right way to do what you are trying to achieve is:

因此,完成您要实现的目标的正确方法是:

#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");
};

Moreover, I bet you are trying to constrict your template to floating points values. In order to do this, you can use the trait std::is_floating_point:

此外,我敢打赌您正试图将您的模板限制为浮点值。为此,您可以使用 trait 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");
};

And as a bonus, take this online example.

作为奖励,以这个在线示例为例

回答by Juraj Blaho

This way it also allows specialization for various types:

通过这种方式,它还允许对各种类型进行专业化:

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

};