I came across the following code (below) on this site
https://www.modernescpp.com/index.php/c-insights-variadic-templates
But this declaration/definition works only with integers and I want to write a version that works with other types like float, double, std::strings and user defined types that overloads "+" operator. However I am struggling to write one.
Please note that the mentioned site has variadic function template based solution that works with different datatypes including floating point types(not tried with user defined types yet). I am looking for a variadic template class based solution. This is purely for learning purpose.
Can someone please help me to get this right?
#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;
}
I wrote this but got stuck
template<typename ...>
struct add;
template<typename T, typename... args>
struct add<T, args...>
{
static constexpr T value = ??//T();//what to write here?
};
Thanks in Advance.
It is also possible to do so for non integer types with some modification!
Templates non-type, non-template parameters should be of integer types or of reference/pointer with a linkage or some limited more possibilities. One can read the full list here Template parameters and template arguments.
Since floating types can not appear as templates non-type, non-template parameters/arguments, the best next option is to take them by reference.
So the struct
becomes like:
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;
};
Values should be stored as constants (with a linkage) first, so before main()
:
const auto v1 = 12; //int
const auto v2 = 54L; //long
const auto v3 = 3.25242; //double
const auto v4 = 75.7256L; //long double
Then they can be used any where:
#include <iostream>
int main(){
std::cout << add<v1, v2, v3, v4>::value << std::endl;
}
Possible output:
144.978
It works not only with (mixed) integer types and (mixed) floating types but also any custom type provided that the custom types satisfy specific properties including having constexpr
constructors and operator +
. It also has to have some sort of type conversion operator or other means to achieve similar functionality.
For example this type can be used:
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;
}
};
Putting it all together:
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;
}
Possible output:
7524.21
Please note the struct add
for C++ versions lower than 17 can only take arguments of a single type and for the type double
would be like:
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;
};
And constants:
const double v1 = 12;
const double v2 = 54L;
const double v3 = 3.25242;
const double v4 = 75.7256l;
Good luck!