如何编写计算整数和的可变参数模板 class 的通用版本
How to write generic version of variadic template class that calculates sum of integers
我在这个网站上看到了下面的代码
https://www.modernescpp.com/index.php/c-insights-variadic-templates
但是这个 declaration/definition 只适用于整数,我想编写一个适用于其他类型的版本,如 float、double、std::strings 和重载“+”运算符的用户定义类型。然而我正在努力写一个。
请注意,上述站点具有基于可变函数模板的解决方案,适用于包括浮点类型在内的不同数据类型(尚未尝试使用用户定义的类型)。我正在寻找基于可变参数模板 class 的解决方案。这纯粹是为了学习目的。
有人可以帮我解决这个问题吗?
#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
作为值。
问题变成:考虑到模板值可能属于不同类型,value
是哪种类型?
我想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; };
我的意思是:不是两个专业化,而是一个主要版本(这是递归的基本情况)和一个专业化(递归情况)。
或者,至少,我认为这是一种简化。
我假设您出于某种原因不想写一个简单的 fold-expression。
我们需要一个 T
类型的实际 值 作为 (non-type) 模板参数。最简单的方法是使用 auto
作为它的类型:
template<auto ...>
struct add;
template<auto t>
struct add<t>
{
static constexpr auto value = t;
};
template<auto t, auto... args>
struct add<t, args...>
{
static constexpr auto value = t + add<args...>::value;
};
演示:
#include <iostream>
#include <string>
int main()
{
std::cout << add<1, 2, 3>::value << '\n';
std::cout << add<1u, 2, -4>::value << '\n';
}
也可以对非整数类型进行一些修改!
模板 non-type、non-template 参数应为整数类型或 reference/pointer 具有链接或一些有限的更多可能性。可以在此处阅读完整列表 Template parameters and template arguments.
由于浮动类型不能作为模板出现 non-type、non-template parameters/arguments,最好的下一个选择是通过引用来获取它们。
所以 struct
变成这样:
template<auto& ...>
struct add{
static constexpr auto value = 0;
};
template<auto& first, auto& ... others>
struct add<first, others...>{
static constexpr auto value = first + add<others ...>::value;
};
值应该首先存储为常量(带有链接),所以在 main()
:
之前
const auto v1 = 12; //int
const auto v2 = 54L; //long
const auto v3 = 3.25242; //double
const auto v4 = 75.7256L; //long double
然后它们可以在任何地方使用:
#include <iostream>
int main(){
std::cout << add<v1, v2, v3, v4>::value << std::endl;
}
可能的输出:
144.978
它不仅适用于(混合)整数类型和(混合)浮点类型,而且适用于任何自定义类型,前提是自定义类型满足特定属性,包括具有 constexpr
构造函数和 operator +
。它还必须具有某种类型转换运算符或其他方法来实现类似的功能。
例如可以使用这种类型:
class custom_type{
const float v;
//this one works too but the first is better for the purpose.
//float v;
public:
template<typename T>
constexpr custom_type(T v_):v(v_){}
template<typename T>
constexpr auto operator +(T o)const{
return o + 7345 + v ;
}
//this one works but the next one is better for the purpose.
//operator auto()const{
//this one works too but the next one is more clear.
//constexpr operator auto()const{
template<typename T>
constexpr operator T()const{
return v;
}
};
综合起来:
template<auto& ...>
struct add{
static constexpr auto value = 0;
};
template<auto& first, auto& ... others>
struct add<first, others...>{
static constexpr auto value = first + add<others ...>::value;
};
class custom_type{
const float v;
public:
template<typename T>
constexpr custom_type(T v_):v(v_){}
template<typename T>
constexpr auto operator +(T o)const{
return o + 7345 + v ;
}
template<typename T>
constexpr operator T()const{
return v;
}
};
const auto v1 = 12; //int
const auto v2 = 54L; //long
const auto v3 = 3.25242; //double
const auto v4 = 75.7256L; //long double
const custom_type v5 = 34.234; //custom_type
#include <iostream>
int main(){
std::cout << add<v1, v2, v3, v4, v5>::value << std::endl;
}
可能的输出:
7524.21
请注意,对于低于 17 的 C++ 版本,struct add
只能采用单一类型的参数,而对于类型 double
则为:
template<const double& ...>
struct add{
static constexpr double value = 0;
};
template<const double& first, const double& ... others>
struct add<first, others...>{
static constexpr double value = first + add<others ...>::value;
};
和常量:
const double v1 = 12;
const double v2 = 54L;
const double v3 = 3.25242;
const double v4 = 75.7256l;
祝你好运!
我在这个网站上看到了下面的代码
https://www.modernescpp.com/index.php/c-insights-variadic-templates
但是这个 declaration/definition 只适用于整数,我想编写一个适用于其他类型的版本,如 float、double、std::strings 和重载“+”运算符的用户定义类型。然而我正在努力写一个。
请注意,上述站点具有基于可变函数模板的解决方案,适用于包括浮点类型在内的不同数据类型(尚未尝试使用用户定义的类型)。我正在寻找基于可变参数模板 class 的解决方案。这纯粹是为了学习目的。
有人可以帮我解决这个问题吗?
#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
作为值。
问题变成:考虑到模板值可能属于不同类型,value
是哪种类型?
我想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; };
我的意思是:不是两个专业化,而是一个主要版本(这是递归的基本情况)和一个专业化(递归情况)。
或者,至少,我认为这是一种简化。
我假设您出于某种原因不想写一个简单的 fold-expression。
我们需要一个 T
类型的实际 值 作为 (non-type) 模板参数。最简单的方法是使用 auto
作为它的类型:
template<auto ...>
struct add;
template<auto t>
struct add<t>
{
static constexpr auto value = t;
};
template<auto t, auto... args>
struct add<t, args...>
{
static constexpr auto value = t + add<args...>::value;
};
演示:
#include <iostream>
#include <string>
int main()
{
std::cout << add<1, 2, 3>::value << '\n';
std::cout << add<1u, 2, -4>::value << '\n';
}
也可以对非整数类型进行一些修改!
模板 non-type、non-template 参数应为整数类型或 reference/pointer 具有链接或一些有限的更多可能性。可以在此处阅读完整列表 Template parameters and template arguments.
由于浮动类型不能作为模板出现 non-type、non-template parameters/arguments,最好的下一个选择是通过引用来获取它们。
所以 struct
变成这样:
template<auto& ...>
struct add{
static constexpr auto value = 0;
};
template<auto& first, auto& ... others>
struct add<first, others...>{
static constexpr auto value = first + add<others ...>::value;
};
值应该首先存储为常量(带有链接),所以在 main()
:
const auto v1 = 12; //int
const auto v2 = 54L; //long
const auto v3 = 3.25242; //double
const auto v4 = 75.7256L; //long double
然后它们可以在任何地方使用:
#include <iostream>
int main(){
std::cout << add<v1, v2, v3, v4>::value << std::endl;
}
可能的输出:
144.978
它不仅适用于(混合)整数类型和(混合)浮点类型,而且适用于任何自定义类型,前提是自定义类型满足特定属性,包括具有 constexpr
构造函数和 operator +
。它还必须具有某种类型转换运算符或其他方法来实现类似的功能。
例如可以使用这种类型:
class custom_type{
const float v;
//this one works too but the first is better for the purpose.
//float v;
public:
template<typename T>
constexpr custom_type(T v_):v(v_){}
template<typename T>
constexpr auto operator +(T o)const{
return o + 7345 + v ;
}
//this one works but the next one is better for the purpose.
//operator auto()const{
//this one works too but the next one is more clear.
//constexpr operator auto()const{
template<typename T>
constexpr operator T()const{
return v;
}
};
综合起来:
template<auto& ...>
struct add{
static constexpr auto value = 0;
};
template<auto& first, auto& ... others>
struct add<first, others...>{
static constexpr auto value = first + add<others ...>::value;
};
class custom_type{
const float v;
public:
template<typename T>
constexpr custom_type(T v_):v(v_){}
template<typename T>
constexpr auto operator +(T o)const{
return o + 7345 + v ;
}
template<typename T>
constexpr operator T()const{
return v;
}
};
const auto v1 = 12; //int
const auto v2 = 54L; //long
const auto v3 = 3.25242; //double
const auto v4 = 75.7256L; //long double
const custom_type v5 = 34.234; //custom_type
#include <iostream>
int main(){
std::cout << add<v1, v2, v3, v4, v5>::value << std::endl;
}
可能的输出:
7524.21
请注意,对于低于 17 的 C++ 版本,struct add
只能采用单一类型的参数,而对于类型 double
则为:
template<const double& ...>
struct add{
static constexpr double value = 0;
};
template<const double& first, const double& ... others>
struct add<first, others...>{
static constexpr double value = first + add<others ...>::value;
};
和常量:
const double v1 = 12;
const double v2 = 54L;
const double v3 = 3.25242;
const double v4 = 75.7256l;
祝你好运!