【问题标题】:Class template for numeric types数字类型的类模板
【发布时间】:2013-01-12 14:28:44
【问题描述】:

如何编写只接受数字类型(intdoublefloat 等)作为模板的类模板?

【问题讨论】:

  • @KonradRudolph 你还想修正标题吗?如果 OP 真的意味着类型或实际上意味着这些类型的常量,我会感到困惑。
  • @pmr 我没有(但我现在做到了),很好。我相当肯定 OP 意味着类型,如果没有其他原因您不能将非整数类型用作非类型模板,并且在谈论非类型模板时这个问题没有任何意义。
  • @KonradRudolph 是的,我的意思是类型。

标签: c++ templates


【解决方案1】:

您可以使用std::is_arithmetic 类型特征。如果您只想启用具有这种类型的类的实例化,请将其与std::enable_if 结合使用:

#include <type_traits>

template<
    typename T, //real type
    typename = typename std::enable_if<std::is_arithmetic<T>::value, T>::type
> struct S{};

int main() {
   S<int> s; //compiles
   S<char*> s; //doesn't compile
}

对于更易于使用的enable_if 版本,以及免费添加disable_if,我强烈建议您阅读this wonderful article

在 C++ 中,上述技术有一个名称,称为“替换失败不是错误”(大多数使用首字母缩写词 SFINAE)。您可以在 wikipediacppreference.com 上阅读有关此 C++ 技术的更多信息。

从 C++20 开始,concepts 使这变得更容易并且不会破坏界面:

#include <concepts>

template<typename T>
concept arithmetic = std::integral<T> or std::floating_point<T>;

template<typename T>
  requires arithmetic<T>
struct S{};
// Shorthand: template<arithmetic T> struct S {};

请注意,有许多用户类型也需要在算术上使用,所以一个更一般的概念涵盖了您正在寻找的操作,而不是类型 您正在寻找的最好是通用接口。

【讨论】:

  • 你可以不用typename Dummy =。此外,我强烈建议在这里使用Wheels,它使代码更加简单:template &lt;typename T, wheels:EnableIf&lt;wheels::IsArithmetic&lt;T&gt;&gt;&gt;
  • @KonradRudolph,你说得对,谢谢。我会在他的enable_if 帖子中添加一个链接以供进一步阅读。
  • 我的错,我忘记了参数包。下面是一个运行示例:stacked-crooked.com/view?id=78592aa7213e78a32094dd8f4c929d2e - 注意EnableIf 后面的...
  • @Ethanabc,它是一个没有名称和默认参数的模板参数,类似于void foo(int = 5);。我们在这里不需要名称,因为该参数仅用于 SFINAE。完全删除它会尝试创建指定类型的非类型参数(enable_if 的“返回”类型),这是无效的,或者至少在我写答案时不是,但概念是无论如何,今年的首选方法。
  • 注意:没有什么可以阻止某人手动指定第二个类型参数,例如S&lt;char*, void&gt;。可以使用具有更详细结构的 SFINAE 来防止这种情况发生,但此时您不妨转向概念。
【解决方案2】:

我发现从 template&lt;typename T, typename = ...&gt; 方法收到的错误消息非常神秘(VS 2015),但发现具有相同类型特征的 static_assert 也可以工作,并让我指定错误消息:

#include <type_traits>

template <typename NumericType>
struct S
{
    static_assert(std::is_arithmetic<NumericType>::value, "NumericType must be numeric");
};

template <typename NumericType>
NumericType add_one(NumericType n)
{
    static_assert(std::is_arithmetic<NumericType>::value, "NumericType must be numeric");
    return n + 1;
}

int main()
{
    S<int> i;
    S<char*> s; //doesn't compile

    add_one(1.f);
    add_one("hi there"); //doesn't compile
}

【讨论】:

  • 当然。最好在此处添加此消息。
  • 这种方法 1. 使 API 少了一个模板参数......并且参数越少看起来更干净 2. static_assert 更容易理解 IMO。然而,这个解决方案的赞成票要少得多。也许other approach 是首选,因为函数签名明确显示了支持的类型。
  • @TrevorBoydSmith NumericType 模板参数真的不如虚拟的 std::enable_if&lt;...&gt; 模板参数那么清晰/明确吗?
  • @TrevorBoydSmith Nah,另一个答案并不像看起来那么受欢迎。它刚刚领先了三年多!
  • @TrevorBoydSmith 你们一起工作还是什么?对于这个老问题,这是一个令人惊讶的行动(尽管我很欣赏赞成票:))
猜你喜欢
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 2018-12-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多