c++ - 如何编写计算整数和的可变参数模板类的通用版本

标签 c++ variadic-templates template-meta-programming

我在这个网站上看到了下面的代码

https://www.modernescpp.com/index.php/c-insights-variadic-templates

但此声明/定义仅适用于整数,我想编写一个适用于其他类型的版本,如 float、double、std::strings 和重载“+”运算符的用户定义类型。但是我正在努力写一个。

请注意,提到的站点具有基于可变函数模板的解决方案,适用于不同的数据类型,包括浮点类型(尚未尝试使用用户定义的类型)。我正在寻找基于可变参数模板类的解决方案。这纯粹是为了学习目的。

有人可以帮我解决这个问题吗?

#include<iostream>

template<int...>
struct add;

template<>
struct add<>
{
  static constexpr int value = 0;
};

template<int i, int... tail>
struct add<i, tail...>
{
  static constexpr int value = i + add<tail...>::value;
};

int main()
{
    std::cout << add<1,2,3,4>::value;
}

我写了这个但是卡住了

template<typename ...>
struct add;

template<typename T, typename... args>
struct add<T, args...>
{
    static constexpr T value = ??//T();//what to write here?
};

提前致谢。

最佳答案

下面的内容呢?

#include <iostream>

template <typename T, T...>
struct add
{ static constexpr T value = 0; };

template <typename T, T head, T ... tail>
struct add<T, head, tail...>
{ static constexpr T value = head + add<T, tail...>::value; };

int main()
 {
    std::cout << add<int, 1, 2, 3, 4>::value << std::endl;
    std::cout << add<long, 10l, 20l, 30l, 40l>::value << std::endl;
 }

或者,也许更好,继承自 std::integral_constant

template <typename T, T...>
struct add : public std::integral_constant<T, T{0}>
{ };

template <typename T, T head, T ... tail>
struct add<T, head, tail...>
   : public std::integral_constant<T, head + add<T, tail...>::value>
{ };

如果你可以使用 C++17,你就不再需要递归了,但你可以使用模板折叠。

template <typename T, T... Is>
struct add : public std::integral_constant<T, (... + Is)>
 { };

C++17 还为您提供了摆脱 typename T 类型参数的机会,使用 auto 作为值。

问题变成:考虑到模板值可能属于不同类型, 是哪种类型?

我想 std::common_type 可以解决这个问题,所以

#include <iostream>
#include <type_traits>

template <auto ... Is>
struct add :
   public std::integral_constant<std::common_type_t<decltype(Is)...>,
                                 (... + Is)>
 { };

int main()
 {
    std::cout << add<1, 2, 3, 4>::value << std::endl;
    std::cout << add<10l, 20l, 30l, 40l>::value << std::endl;
 }

或者,也许,简单地使用 decltype((... + Is))

template <auto ... Is>
struct add :
   public std::integral_constant<decltype((... + Is)), (... + Is)>
 { };

题外话:原来的add可以稍微简化如下

template <int...>
struct add
 { static constexpr int value = 0; };

template <int i, int... tail>
struct add<i, tail...>
 { static constexpr int value = i + add<tail...>::value; };

我的意思是:不是两个特化,而是一个主要版本(这是递归的基本情况)和一个特化(递归情况)。

或者,至少,我认为这是一种简化。

关于c++ - 如何编写计算整数和的可变参数模板类的通用版本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56281654/

相关文章:

c++ - 在 C++ 中,我无法掌握指针和类

c++ - 如何删除可变参数模板构造函数的复制/移动实例化

c++ - 使用元编程展开嵌套循环

c++ - 如何在 C++ 中将运行时类型鉴别器映射到模板实例(无需手动枚举它们)?

c++ - 带有 'using' 的可变参数模板和类型定义

c++ - std::bind 可变参数模板、绑定(bind)参数和占位符

c++ - CRTP 基类型使用的成员变量应该在派生类型中吗?

c++ - 如何创建 DDE 服务器

c++ - 了解 shared_ptr

c++ - 用于创建格式化字符串的可变参数模板