Variadic templates, size_t - c++

How can I solve this problem?
#include <iostream>
using namespace std;
template<size_t I, size_t... T>
void fun()
{
cout<<I<<endl;
fun<T...>();
}
template<size_t I>
void fun()
{
cout<<I<<endl;
}
int main()
{
fun<1, 2>();
fun<3>();
return 0;
}
errors:
|21|error: call of overloaded 'fun()' is ambiguous|
|21|note: candidates are:|
|5|note: void fun() [with unsigned int I = 3u;
unsigned int ...T = {}]| |12|note: void fun() [with unsigned int I =
3u]| In instantiation of 'void fun() [with unsigned int I = 2u;
unsigned int ...T = {}]':| |8|required from 'void fun() [with
unsigned int I = 1u; unsigned int ...T = {2u}]'| |20|required from
here| |8|error: no matching function for call to 'fun()'| |8|note:
candidate is:| |5|note: template<unsigned int I, unsigned int ...T>
void fun()| |5|note: template argument deduction/substitution
failed:| |8|note: couldn't deduce template parameter 'I'|

Make the variadic version only accept two or more template arguments.
template<size_t I>
void fun()
{
cout<<I<<endl;
}
template<size_t I1, size_t I2, size_t... T>
void fun()
{
cout<<I1<<endl;
fun<I2, T...>();
}

Related

Why can't the .size() of an array passed to a function as a constant reference be used as a template parameter?

I can't seem to figure out why the following code doesn't work:
#include <array>
template <long unsigned int s> void a() {}
template <long unsigned int s> void b(const std::array<int, s>& arr) {
a<arr.size()>(); // error: no matching function for call to 'a'
}
int main() {
const std::array<int, 2> arr {{0, 0}};
a<arr.size()>(); // Works
b<arr.size()>(arr);
return 0;
}
GCC fails with the following:
test.cpp: In instantiation of ‘void b(const std::array<int, s>&) [with long unsigned int s = 2]’:
test.cpp:13:22: required from here
test.cpp:6:18: error: no matching function for call to ‘a<(& arr)->std::array<int, 2>::size()>()’
6 | a<arr.size()>(); // Doesn't
| ~~~~~~~~~~~~~^~
test.cpp:3:37: note: candidate: ‘template<long unsigned int s> void a()’
3 | template <long unsigned int s> void a() {}
| ^
test.cpp:3:37: note: template argument deduction/substitution failed:
test.cpp:6:18: error: ‘arr’ is not a constant expression
6 | a<arr.size()>(); // Doesn't
| ~~~~~~~~~~~~~^~
test.cpp:6:15: note: in template argument for type ‘long unsigned int’
6 | a<arr.size()>(); // Doesn't
| ~~~~~~~~^~
I assume the ‘arr’ is not a constant expression part is most relevant, but I don't understand why the same line works in main() (is it a constant expression there?), and why passing arr as a const copy (rather than a reference) also resolves the issue.
PS: I know that I can just use a<s>();, but I'm just trying to figure out what this error means.
Maybe in C++2X, it will work with consteval functitons.
For non-reference argument it works https://godbolt.org/z/Wx9va54z5.
I think it is fine to pass std::array of built-ins by value in general anyway.
(This works in GCC and clang.)
#include <array>
template <long unsigned int s> void a() {}
template <long unsigned int s> void b(std::array<int, s> arr) {
a<arr.size()>(); // ok
}
int main() {
const std::array<int, 2> arr = {};
a<arr.size()>(); // Works
b<arr.size()>(arr);
return 0;
}
To answer the question in your comment #acumandr, yes, a static and constexpr size() member function in std::array would work(!), even for const& argument. https://godbolt.org/z/anP1e9qEr
CORRECTION: This is correct only for GCC, in clang doesn't work https://godbolt.org/z/65d5G9Yfo , Thanks #IlCapitano
#include <array>
template<class T, std::size_t D>
struct MyArray{
static constexpr std::size_t size(){return D;}
};
template <long unsigned int s> void a() {}
template <long unsigned int s> void b(MyArray<int, s> const& arr) {
a<arr.size()>(); // ok
}
int main() {
const MyArray<int, 2> arr = {};
a<arr.size()>(); // Works
b<arr.size()>(arr);
return 0;
}
which makes even more puzzling why std::array doesn't have a static (and constexpr) size member.
2.5) CORRECTION: This is correct only for GCC, in clang doesn't work https://godbolt.org/z/65d5G9Yfo , Thanks #IlCapitano
In clang, a static funciton works but not passing the instance, which kind of defeats the purpose:
https://godbolt.org/z/En13aEWPz
#include <array>
template<class T, std::size_t D>
struct MyArray{
static constexpr std::size_t size(){return D;}
};
template <long unsigned int s> void a() {}
template <long unsigned int s> void b(MyArray<int, s> const& arr) {
a<std::decay_t<decltype(arr)>::size()>(); // error: no matching function for call to 'a'
}
int main() {
const MyArray<int, 2> arr = {};
a<arr.size()>(); // Works
b<arr.size()>(arr);
return 0;
}
using std::tuple_size<decltype(...)> (or s itself) is a good workaround https://godbolt.org/z/K9xxKa1Px
#include <array>
template <long unsigned int s> void a() {}
template <long unsigned int s> void b(std::array<int, s> arr) {
a<std::tuple_size<decltype(arr)>::value /*or just s*/>(); // ok
}
int main() {
const std::array<int, 2> arr = {};
a<arr.size()>(); // Works
b<arr.size()>(arr);
return 0;
}

conversion error from make_integer_sequence to integer_sequence

The following program does not compile:
#include <utility>
#include <iostream>
#define N 4
template <unsigned int I>
unsigned int g() { return I; }
template <unsigned int... I>
unsigned int f(std::integer_sequence<unsigned int, I...> = std::make_integer_sequence<unsigned int, N>{})
{
return (g<I>() + ...);
}
int main()
{
std::cout << f() << std::endl;
return 0;
}
Test it live on Coliru.
With gcc the error is
main.cpp: In function 'unsigned int f(std::integer_sequence<unsigned
int, I ...>) [with unsigned int ...I = {}]':
main.cpp:17:18: error: could not convert
'std::make_integer_sequence<unsigned int, 4>{}' from
'integer_sequence<[...],'nontype_argument_pack' not supported by
dump_expr>' to
'integer_sequence<[...],'nontype_argument_pack' not supported by
dump_expr>'
A similar conversion error is reported with clang++:
error: no viable conversion from 'std::make_integer_sequence<unsigned
int, 4>' (aka '__make_integer_seq<integer_sequence, unsigned int,
4U>') to 'std::integer_sequence'
Strangely enough, however, if I remove the default parameter, and pass the same expression to f, the program compiles and gives the corrected output:
#include <utility>
#include <iostream>
#define N 4
template <unsigned int I>
unsigned int g() { return I; }
template <unsigned int... I>
unsigned int f(std::integer_sequence<unsigned int, I...>)
{
return (g<I>() + ...);
}
int main()
{
std::cout << f(std::make_integer_sequence<unsigned int, N>{}) << std::endl;
return 0;
}
See it live on Coliru.
What's the problem/difference with the first code?
I admit, I do not understand the error message. The reason the second version compiles but not the first is that template parameters cannot be deduced from default arguments but from function parameters. Consider this simpler example:
#include <utility>
#include <iostream>
template <unsigned int>
struct foo {};
template <unsigned int x>
foo<x> make_foo(){ return {};}
template <unsigned int x>
unsigned int f(foo<x> = make_foo<4>())
{
return 42;
}
int main()
{
std::cout << f() << std::endl;
return 0;
}
Here the error is a little more descriptive:
<source>: In function 'int main()':
<source>:18:18: error: no matching function for call to 'f()'
18 | std::cout << f() << std::endl;
| ^
<source>:11:14: note: candidate: 'template<unsigned int x> unsigned int f(foo<x>)'
11 | unsigned int f(foo<x> = make_foo<4>())
| ^
<source>:11:14: note: template argument deduction/substitution failed:
<source>:18:18: note: couldn't deduce template parameter 'x'
18 | std::cout << f() << std::endl;
| ^
The main purpose of make_integer_sequence<unsigned int,N> is to make the transition from a single N to the pack in std::integer_sequence<unsigned int, I...> as you do it in your second example.
With a level of indirection you avoid that the caller must pass the parameter:
// ...
template <unsigned int... I>
unsigned int f(std::integer_sequence<unsigned int, I...>)
{
return (g<I>() + ...);
}
template <unsigned int X = N>
unsigned int f_wrap()
{
return f(std::make_integer_sequence<unsigned int,N>{});
}
int main()
{
std::cout << f_wrap() << std::endl;
return 0;
}
Live Demo

Problem with std::index_sequence_for as default argument?

The following C++20 program:
#include <utility>
#include <cstddef>
template<typename... Args>
class C {
template<size_t... I>
static void call(
std::index_sequence<I...> = std::index_sequence_for<Args...>{}
) {}
};
int main() {
C<long int>::call();
}
fails to compile with error message:
test.cc: In static member function ‘static void C<Args>::call(std::index_sequence<I ...>) [with long unsigned int ...I = {}; Args = {long int}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int>]’:
test.cc:11:20: error: could not convert ‘std::index_sequence_for<long int>{}’ from ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’ to ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’
11 | C<long int>::call();
| ^
| |
| integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>
test.cc:11:20: note: when instantiating default argument for call to ‘static void C<Args>::call(std::index_sequence<I ...>) [with long unsigned int ...I = {}; Args = {long int}; std::index_sequence<I ...> = std::integer_sequence<long unsigned int>]’
test.cc: In function ‘int main()’:
test.cc:11:20: error: could not convert ‘std::index_sequence_for<long int>{}’ from ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’ to ‘integer_sequence<[...],#‘nontype_argument_pack’ not supported by dump_expr#<expression error>>’
Any ideas?
Update:
My current best workaround is to factor out default argument into two functions like:
template<typename... Args>
class C {
static void call() {
_call(std::index_sequence_for<Args...>{});
}
template<size_t... I>
static void _call(std::index_sequence<I...>) {}
};
This seems to work around compiler bug (if that's what it is).
Update 2:
The below program fails for the same reason the original one does:
template<typename T> void f(T x = 42) {}
int main() { f(); }
so it's a feature not a bug.
In general template argument deduction + default function arguments cause a lot of trouble. To simply fix it you can go with this:
#include <utility>
#include <cstddef>
template<typename... Args>
class C {
public:
static void call() {
call_impl(std::index_sequence_for<Args...>{});
}
private:
template<size_t... I>
static void call_impl(std::index_sequence<I...> ) {
}
};
int main() {
C<long int>::call();
}
In C++20 you can also write a templated lambda to do exactly that without creating a new function:
//...
static void call() {
return [&]<size_t... Is>(std::index_sequence<Is...>) {
/* your code goes here... */
}( std::index_sequence_for<Args...>{} );
}

Value as arguments for variadic template

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; }
};

c++ template class member function specialization

I have a problem where I want to specialize a template member function of a template class in the code below. The answer to this question explicit specialization of template class member function seems to suggest that it can't be done. Is that correct, and if so, is there any work around I can use so that by inline inc functions get expanded at compile time?
Many thanks!
#include <iostream>
#include <cstdio>
template <class IT, unsigned int N>
struct IdxIterator {
private:
int startIdx[N], endIdx[N];
int curIdx[N];
IT iter;
public:
IdxIterator(IT it, int cur[], int start[], int end[]): iter(it) {
for (int i = 0; i < N; i++) {
curIdx[i] = cur[i];
startIdx[i] = start[i];
endIdx[i] = end[i];
}
}
template <int dim>
inline void inc() {
curIdx[dim]++;
if (curIdx[dim] > endIdx[dim]) {
if (dim > 0) {
curIdx[dim] = startIdx[dim];
inc<dim-1>();
}
}
}
// how to declare this specialization?
template <> template <>
inline void inc<-1>() {
std::cerr << "IdxIterator::inc(" << -1 << ") dim out of bounds!\n";
throw 1;
}
inline IdxIterator<IT, N> operator++() {
iter++;
inc<N-1>();
return *this;
}
};
int main(int argc, char** argv) {
int *buf = new int[100];
int start[1], end[1];
start[0] = 0; end[0] = 99;
IdxIterator<int*, 1> it(buf, start, start, end);
++it;
return 0;
}
G++ spits out:
test2.cpp:32:13: error: explicit specialisation in non-namespace scope
‘struct IdxIterator’ test2.cpp:32:25: error: explicit
specialisation in non-namespace scope ‘struct IdxIterator’
test2.cpp:33:23: error: template-id ‘inc<-0x00000000000000001>’ in
declaration of primary template test2.cpp: In member function ‘void
IdxIterator::inc() [with int dim = -0x000000000000003fe, IT =
int*, unsigned int N = 1u]’: test2.cpp:27:9: error: template
instantiation depth exceeds maximum of 1024 (use -ftemplate-depth= to
increase the maximum) instantiating ‘void IdxIterator::inc()
[with int dim = -0x000000000000003ff, IT = int*, unsigned int N = 1u]’
test2.cpp:27:9: recursively instantiated from ‘void IdxIterator::inc() [with int dim = -0x00000000000000001, IT = int*, unsigned
int N = 1u]’ test2.cpp:27:9: instantiated from ‘void IdxIterator::inc() [with int dim = 0, IT = int*, unsigned int N = 1u]’
test2.cpp:41:5: instantiated from ‘IdxIterator
IdxIterator::operator++() [with IT = int*, unsigned int N =
1u]’ test2.cpp:53:5: instantiated from here
test2.cpp: At global scope: test2.cpp:22:15: warning: inline function
‘void IdxIterator::inc() [with int dim = -0x000000000000003ff,
IT = int*, unsigned int N = 1u]’ used but never defined [enabled by
default]
There may be a better way in C++11, but you can always go via overloading instead of specialization:
template <int N>
struct num { };
class A
{
template <int N>
void f(num <N>) { };
void f(num <-1>) { };
public:
template <int N>
void f() { f(num <N>()); };
};
You can do what the compiler error message suggests:
template <class IT, unsigned int N>
struct IdxIterator {
private:
template <int dim>
inline void inc() {
curIdx[dim]++;
if (curIdx[dim] > endIdx[dim]) {
if (dim > 0) {
curIdx[dim] = startIdx[dim];
inc<dim-1>();
}
}
}
};
template <> template <>
inline void IdxIterator::inc<-1>() {
std::cerr << "IdxIterator::inc(" << -1 << ") dim out of bounds!\n";
throw 1;
}
ie move the definition to namespace-scope.
Create a helper struct outside of class
template<dim>
struct inc {
template<class cur, end>
inline static void foo(cur curIdx, end endIdx) {
curIdx[dim]++;
if (curIdx[dim] > endIdx[dim]) {
inc<dim-1>::foo(curIdx, endIdx);
}
}
};
template<>
struct inc<0> {
template<class cur, end>
inline static void foo(cur, end) {
//terminate
}
};
class IdxIterator {
template<int i>
void inc() {
static_assert(i > 0, "error out of bounds");
int<i>::foo(/*params*/);
}
};
Note if you are using the GCC you may __attribute__((always_inline))to force inlining.