Value as arguments for variadic template - c++

I'm trying to make a sum function using variadic template.
#include <iostream>
int sum() {
return 0;
}
template <int first, int ...Rest>
int sum() {
return first + sum<Rest...>();
}
int main() {
sum<1, 2, 3>();
}
But I got an error like this:
test.cc: In instantiation of 'int sum() [with int first = 3; int ...Rest = {}]':
test.cc:10:31: recursively required from 'int sum() [with int first = 2; int ...Rest = {3}]'
test.cc:10:31: required from 'int sum() [with int first = 1; int ...Rest = {2, 3}]'
test.cc:14:17: required from here
test.cc:10:31: error: no matching function for call to 'sum<>()'
return first + sum<Rest...>();
~~~~~~~~~~~~^~
test.cc:9:5: note: candidate: 'template<int first, int ...Rest> int sum()'
int sum() {
^~~
test.cc:9:5: note: template argument deduction/substitution failed:
test.cc:10:31: note: couldn't deduce template parameter 'first'
return first + sum<Rest...>();
so I changed
int sum { return 0; }
to
template<int first>
int sum { return first; }
but I got an another error:
test.cc:11:31: error: call of overloaded 'sum<3>()' is ambiguous
return first + sum<Rest...>();
~~~~~~~~~~~~^~
What should I do?

Your issue here is that sum<Rest...>() when Rest is empty won't call int sum() because that function is not a template.
When you change it to
template<int first>
int sum { return first; }
then the issue becomes that template<int first> int sum and template <int first, int ...Rest> int sum() with Rest being empty resolve to being the same function. There are no rules about a tie break here so you get a compiler error.
The old way to fix this was to just add another template parameter to the variadic template giving you an overload set of
template <int first>
int sum() {
return 0;
}
template <int first, int second, int ...Rest>
int sum() {
return first + sum<second, Rest...>();
}
and with that once Rest is empty the only viable function to call is template <int first> int sum()
Now that we have fold expressions this isn't needed anymore and you can just use
template <int... Vals>
int sum() {
static_assert(sizeof...(Vals) > 0, "You must provide at least one template parameter");
return (... + Vals);
}

In C++17, you might do:
template <int first, int ...Rest>
int sum() {
return (first + ... + Rest);
}
Alternative would be to use class and specialization:
template <int N, int Is...>
struct sum
{
int operator () () const { return N + sum<Is...>{}(); }
};
template <int N>
struct sum<N>
{
int operator () () const { return N; }
};

Related

Conditionally enable member function depending on template parameter

I'm struggling to get the below code to compile. I want to enable foo function for class A only when N=3.
#include <iostream>
template <size_t N>
class A
{
public:
template <size_t n = N, std::enable_if_t<(n == 3)>* = nullptr> int foo(int a);
};
template<size_t N>
template <size_t n = N, std::enable_if_t<(n == 3)>* = nullptr>
int A<N>::foo(int a)
{
return a * 4;
}
int main()
{
A<3> a1;
std::cout << a1.foo(10) << std::endl;
// the below should fail to compile
// A<4> a2;
// std::cout << a2.foo(7) << std::endl;
}
Output
<source>:12:20: error: default argument for template parameter for class enclosing 'int A<N>::foo(int)'
12 | int A<N>::foo(int a)
| ^
Whenever you separate a function's declaration and definition, whether it is a template function or not, default argument values can only be in the declaration, not in the definition. So, simply remove the default values from foo's definition, eg:
#include <iostream>
template <size_t N>
class A
{
public:
template <size_t n = N, std::enable_if_t<(n == 3)>* = nullptr> int foo(int a);
};
template<size_t N>
template <size_t n, std::enable_if_t<(n == 3)>*>
int A<N>::foo(int a)
{
return a * 4;
}
Online Demo

How to specialize template using operator?

I want to sum the number from 1 to N-1 by TMP. so I wrote a source code as shown below, but an error template argument '(number - 1)' involves template parameter(s) occurred. Do you happen to know how to deal with this?
template <int number, int i = 1>
class Sum {
public:
static const int result = i + Sum<number, i + 1>::result;
};
template <int number>
class Sum<number, number - 1> {
public:
static const int result = number - 1;
};
int main () {
const int result = Sum<10>::result;
return 0;
}
GCC still follows the rule:
Non-type argument expression cannot use the name of the template parameter except when it is exactly the name of the template parameter.
To solve the problem using template specialization, you can wrap the second non-type template parameter into an std::integral_constant to make it a type template parameter:
template<int number, class i = std::integral_constant<int, 1>>
struct Sum {
static constexpr int value = i() + Sum<number,
std::integral_constant<int, i() + 1>>::value;
};
template<int number>
struct Sum<number, std::integral_constant<int, number - 1>> {
static constexpr int value = number - 1;
};
static_assert(Sum<10>::value == 45);
Alternatively, you can use if constexpr and no partial specialization:
template<int number, int i = 1>
struct Sum {
static constexpr int value = [] {
if constexpr (number == i + 1)
return i;
else
return i + Sum<number, i + 1>::value;
}();
};
static_assert(Sum<10>::value == 45);
Yet another way is given by fold expressions:
template<class> struct Sum_impl;
template<int... numbers>
struct Sum_impl<std::integer_sequence<int, numbers...>> {
static constexpr int value = (... + numbers);
};
template<int number>
struct Sum : Sum_impl<std::make_integer_sequence<int, number>> {};

Non-type template parameters, constructor and deduction guide

I want to have a struct template, that is defined by particular values of its components passed to it during construction, such that different values would create different C++ data types, and thought non-type template parameters may be useful for that.
Something like this (just a simple example to show the issue, the real struct will be more complex):
enum ElementType
{
TYPE1,
TYPE2
};
template<ElementType elementType, int size>
struct DataType
{
DataType(ElementType et = elementType, int s = size):
elementType_(et),
size_(s)
{
}
ElementType elementType_;
int size_;
};
int main()
{
auto d1 = DataType(ElementType::TYPE1, 1);
}
I try to build this with g++-8 -std=c++17 and it gives me the following error:
./main.cpp:23:42: error: class template argument deduction failed:
auto d1 = DataType(ElementType::TYPE1, 1);
^
../main.cpp:23:42: error: no matching function for call to ‘DataType(ElementType, int)’
../main.cpp:12:2: note: candidate: ‘template<ElementType elementType, int size> DataType(ElementType, int)-> DataType<elementType, size>’
DataType(ElementType et = elementType, int s = size):
^~~~~~~~
../main.cpp:12:2: note: template argument deduction/substitution failed:
../main.cpp:23:42: note: couldn't deduce template parameter ‘elementType’
auto d1 = DataType(ElementType::TYPE1, 1);
^
../main.cpp:23:42: error: expression list treated as compound expression in functional cast [-fpermissive]
../main.cpp:23:42: warning: left operand of comma operator has no effect [-Wunused-value]
Note that I cannot use type template arguments, since the two types of the arguments are fixed (ElementType and int), but DataType(ElementType::TYPE1, 1) must be of different type than DataType(ElementType::TYPE1, 2) and DataType(ElementType::TYPE1, 1) must be different than DataType(ElementType::TYPE2, 1).
You can define your template like this:
template<ElementType elementType, int size>
struct DataType
{
const ElementType elementType_ = elementType;
const int size_ = size;
};
And create an instance of it like this:
auto d1 = DataType<ElementType::TYPE1, 1>();
Demo
To make use of deduction the value you pass to the constructor needs to be a constant expression. Unfortunately values passed as parameter loose their constexpr properties. To prevent this behavior you can pass the values wrapped in types e.g. using std::integral_constant.
Exemplary usage:
#include <type_traits>
enum ElementType
{
TYPE1,
TYPE2
};
template<ElementType elementType, int size>
struct DataType
{
DataType(std::integral_constant<ElementType, elementType>, std::integral_constant<int, size> ic):
elementType_(elementType),
size_(ic)
{
}
ElementType elementType_;
int size_;
};
int main()
{
auto d1 = DataType(std::integral_constant<ElementType, TYPE1>{}, std::integral_constant<int, 1>{});
}
[live demo]
To make it more convenient to use you could wrap around integral const with constexpr suffix operators:
#include <type_traits>
enum ElementType
{
TYPE1,
TYPE2
};
template <class... Ts>
constexpr int ival(Ts... Vs) {
char vals[sizeof...(Vs)] = {Vs...};
int result = 0;
for (int i = 0; i < sizeof...(Vs); i++) {
result *= 10;
result += vals[i] - '0';
}
return result;
}
template <class T, class... Ts>
constexpr ElementType etval(T V, Ts... Vs) {
if (V == '1')
return TYPE1;
if (V == '2')
return TYPE2;
}
template <char... Vs>
std::integral_constant<int, ival(Vs...)> operator""_i() {
return {};
}
template <char... Vs>
std::integral_constant<ElementType, etval(Vs...)> operator""_et() {
return {};
}
template<ElementType elementType, int size>
struct DataType
{
DataType(std::integral_constant<ElementType, elementType>, std::integral_constant<int, size> ic):
elementType_(elementType),
size_(ic)
{
}
ElementType elementType_;
int size_;
};
int main()
{
auto d1 = DataType(1_et, 1_i);
}
[live demo]

Ambiguous call to variadic template function with no parameters?

When running this:
template <typename T>
struct CodeByType
{
static const int32_t Value = 7;
};
template <>
struct CodeByType<int>
{
static const int32_t Value = 1;
};
template <typename Arg, typename... Args>
int32_t Sum()
{
// The compiler complains on this line
return Sum<Arg>() + Sum<Args...>();
}
template <typename Arg>
int32_t Sum()
{
return CodeByType<Arg>::Value;
}
int main()
{
auto sum = Sum<int, char, double>();
}
I'm getting:
Error C2668 'Sum': ambiguous call to overloaded function
Can someone please explain why and how to overcome it?
This looks awfully similar to the below code, which does compile, so I suppose it has something to do with Sum not accepting any actual parameters.
template <typename T>
T adder(T first) {
return first;
}
template<typename T, typename... Args>
T adder(T first, Args... rest) {
return first + adder(rest...);
}
int main()
{
auto sum = adder(1, 7);
}
If you reduce your code to just:
Sum<int>();
You get a more helpful error message:
31 : <source>:31:16: error: call to 'Sum' is ambiguous
auto sum = Sum<int>();
^~~~~~~~
17 : <source>:17:9: note: candidate function [with Arg = int, Args = <>]
int32_t Sum()
^
24 : <source>:24:9: note: candidate function [with Arg = int]
int32_t Sum()
^
1 error generated.
So it is clearer that there is an overload ambiguity between the first overload with Args = <> and the second one. Both are viable.
One would might think as specialization for a solution:
template <typename Arg>
int32_t Sum<Arg>()
{
return CodeByType<Arg>::Value;
}
which would indeed solve the issue, had it been allowed by the standard. Partial function specializations are not allowed.
C++17 solution:
This is the most elegant solution:
constexpr if to the rescue:
template <typename Arg, typename... Args>
int32_t Sum()
{
if constexpr(sizeof...(Args) == 0)
return CodeByType<Arg>::Value;
else
return Sum<Arg>() + Sum<Args...>();
}
C++14 solution
We use SFINAE to enable/disable the function we want. Please note the function definition order had to be reversed.
template <typename Arg, typename... Args>
auto Sum() -> std::enable_if_t<(sizeof...(Args) == 0), int32_t>
{
return CodeByType<Arg>::Value;
}
template <typename Arg, typename... Args>
auto Sum() -> std::enable_if_t<(sizeof...(Args) > 0), int32_t>
{
return Sum<Arg>() + Sum<Args...>();
}
C++11 solution
just replace std::enable_if_t<> with typename std::enable_if<>::type
In c++17, it would simply be
template <typename... Args>
int32_t Sum()
{
return (CodeByType<Args>::Value + ...); // Fold expression
}
In C++11, you may do:
template <typename... Args>
int32_t Sum()
{
int32_t res = 0;
const int32_t dummy[] = {0, (res += CodeByType<Args>::Value)...};
static_cast<void>(dummy); silent warning about unused variable
return res;
}
My memories of the template mechanism are old but if I recall correctly, their information is erased at a certain point in the compilation process.
My guess is that in the second case, the functions get distinguished not by the difference in the template types, but by the difference in the arguments.
In your case, you have no arguments, so stripped of the template information the two overloaded versions are equal and it cannot distinguish between them when you call it.

Define friend function template of class template

I want to define a function template of a class template. The code looks like this.
template<int M>
struct test{
private:
int value;
template<int N = 2 * M>
friend auto foo(test const t){
test<N> r;
r.value = t.value;
return r;
}
};
int main(){
test<1> t;
foo(t);// expected to return test<2>
foo<1>(t);// expected to return test<1>
foo<3>(t);// expected to return test<3>
}
But it won't compile. Compared with previous problems, the following lists the differences.
The result of the function template involves another instatiation of the class template. It seems that the function template has to be defined outside. But I am not sure.
The function template uses default template arguments. So, if the function template is defined outside the class, a helper function template is required.
Compiling Errors with g++ -std=c++1z:
a.cpp: In instantiation of 'auto foo(test<M>) [with int N = 2; int M = 1]':
a.cpp:16:10: required from here
a.cpp:4:9: error: 'int test<2>::value' is private
int value;
^
a.cpp:9:17: error: within this context
r.value = t.value;
^
a.cpp: In instantiation of 'auto foo(test<M>) [with int N = 3; int M = 1]':
a.cpp:18:13: required from here
a.cpp:4:9: error: 'int test<3>::value' is private
int value;
^
a.cpp:9:17: error: within this context
r.value = t.value;
^
A possible workaround, yet not correct either.
template<int M>
struct test{
private:
int value;
template<int NA, int NR>
friend test<NR> foo_impl(test<NA> const&);
};
template<int NA, int NR>
test<NR> foo_impl(test<NA> const& t){
test<NR> r;
r.value = t.value;
return r;
}
template<int NR, int NA>
auto foo(test<NA> const& t){
return foo_impl<NA, NR>;
}
template<int NA>
auto foo(test<NA> const& t){
return foo_impl<NA, NA * 2>(t);
}
int main(){
test<1> t;
foo(t);
foo<3>(t);
foo<1>(t);
}
Error:
t.cpp: In function 'int main()':
t.cpp:31:13: error: call of overloaded 'foo(test<1>&)' is ambiguous
foo<1>(t);
^
t.cpp:18:6: note: candidate: auto foo(const test<NR>&) [with int NR = 1; int NA = 1]
auto foo(test<NA> const& t){
^
t.cpp:23:6: note: candidate: auto foo(const test<NA>&) [with int NA = 1]
auto foo(test<NA> const& t){
^
After your edit, one possible way (which may not be better than your workaround - but work for all call) would be to use a default value for the parameter N:
template<int M>
struct test{
private:
int value;
template<int K, int U, int P>
friend test<P> foo(test<U> const t);
};
template <int N = 0, int M, int P = ((N == 0) ? M * 2 : N)>
test<P> foo (test<M> const t) {
test<P> r;
r.value = t.value;
return r;
}
int main(){
test<1> t;
test<2> p1 = foo(t);
test<3> p2 = foo<3>(t);
test<1> p3 = foo<1>(t);
}
This may not be prettier than your version...
The problem here is that you are declaring foo<N> a friend of test<M> while you want it to be a friend of any test<...>. You should do the following:
template<int M>
struct test{
private:
int value;
template<int U, int K>
friend test<K> foo(test<U> const t);
};
template <int M, int N = 2 * M>
test<N> foo (test<M> const t) {
test<N> r;
r.value = t.value;
return r;
}
int main(){
test<1> t;
foo(t);
}
Here you are saying:
Any function test<K> foo<U, K> (test<U> const) is a friend of any test<...>.