Traversing variadic templates - c++

I am interested in printing out a variadic number of templated arguments.
So far I have implemented the code below but run into the following compile-time errors
./include/AView.hpp:46:5: error: call to member function 'indexcalc2' is ambiguous
indexcalc2<Strs...>();
^~~~~~~~~~~~~~~~~~~
./include/AView.hpp:46:5: note: in instantiation of function template specialization 'myView<double, 2, 1, 2, 3, 4,
5>::indexcalc2<4, 5>' requested here
./include/AView.hpp:46:5: note: in instantiation of function template specialization 'myView<double, 2, 1, 2, 3, 4,
5>::indexcalc2<3, 4, 5>' requested here
./include/AView.hpp:52:5: note: in instantiation of function template specialization 'myView<double, 2, 1, 2, 3, 4,
5>::indexcalc2<2, 3, 4, 5>' requested here
indexcalc2<Strides...>();
^
main.cpp:23:9: note: in instantiation of member function 'myView<double, 2, 1, 2, 3, 4, 5>::indexcalc' requested here
A.indexcalc();
^
./include/AView.hpp:36:8: note: candidate function [with Str0 = 5]
void indexcalc2() const
^
./include/AView.hpp:43:8: note: candidate function [with Str0 = 5, Strs = <>]
void indexcalc2() const
The idea here is to create a layout struct with a get method that will output the first template argument stride. I then created a second struct called view with an indexcalc method which would generate a layout, print the stride, and recursively peal template arguments by calling indexcalc2.
Unfortunately, I don't quite have the correct implementation and wondering if there might be suggestions.
template<size_t... Strides>
struct layout
{
static size_t get(size_t idx0) {return idx0;};
};
template<size_t stride0, size_t... Strides>
struct layout<stride0, Strides...> : layout<Strides...>
{
static size_t get()
{
std::cout<<"Stride is : "<<stride0<<std::endl;
return stride0;
}
};
template<typename T, size_t DIM,size_t Stride0, size_t... Strides>
struct myView
{
myView() {};
template<size_t Str0>
void indexcalc2() const
{
std::cout<<layout<Str0>::get()<<std::endl;
std::cout<<"End"<<std::endl;
}
template<size_t Str0, size_t... Strs>
void indexcalc2() const
{
std::cout<<layout<Str0,Strs...>::get()<<std::endl;
indexcalc2<Strs...>();
}
void indexcalc() const
{
std::cout<<layout<Stride0, Strides...>::get()<<std::endl;
indexcalc2<Strides...>();
}
};
int main()
{
struct myView<double,2,1,2,3,4,5> A;
A.indexcalc();
return 0;
}

You have multiple problems here:
template<size_t Str0> void indexcalc2() const;
template<size_t Str0, size_t... Strs> void indexcalc2() const;
will result in the same instance if Strs contains no elements. So you have an ambiguous instance here which is already complained by the compiler:
./include/AView.hpp:46:5: error: call to member function 'indexcalc2' is ambiguous
indexcalc2<Strs...>();
So the idea by unwinding a parameter set is always to have an empty specialization like:
template<> void indexcalc2() const;
so that a call from
indexcalc2<Strs...>();
goes to that specialization if Strs is empty.
But after this you will run into the next trouble:
Specialization of templates can not be done in the class scope. So you must specialize outside like:
template<> void myView::indexcalc2<>() const;
But your myView is also a template and it is not allowed to specialize your method without fully specialize the class parameters!
If you go with c++17 you simply can use constexpr ifto get rid of all that problems, but in c++11 you have to go over specializing with an encapsulating class.
Your templated class with templated methods is to complex to simply write down a complete solution here for you.

Related

c++ passing a pointer to a template function as template

I have this iter function that takes a pointer to value_type, a size_type, and a function pointer fun_type that is supposed to take a value_type& as parameter:
template <
class value_type,
class size_type,
class fun_type
> void iter(value_type *arr, size_type size, fun_type function)
{ while (size--) function(arr[size]); }
It works fine until we have a function that has a template, let's say for example we want to use this function:
template <
class T
> void print(const T &value) { std::cout << value << std::endl; }
Then we get this compilation error:
main.cpp:35:1: error: no matching function for call to 'iter'
iter( tab, 5, print );
^~~~
./iter.hpp:17:8: note: candidate template ignored: couldn't infer template argument 'fun_type'
> void iter(value_type *arr, size_type size, fun_type function)
^
main.cpp:36:1: error: no matching function for call to 'iter'
iter( tab2, 5, print );
^~~~
./iter.hpp:17:8: note: candidate template ignored: couldn't infer template argument 'fun_type'
> void iter(value_type *arr, size_type size, fun_type function)
How could I make fun_type work with every function no matter the template and the return type of the function?
Your iter function template requires a function for its third template parameter; but print (on its own) is not a function – it's a function template, and the compiler simply cannot deduce what template parameter to use in order to actually create a function … so you need to tell it! Just add the type of the tab array/pointer as that template parameter:
int main()
{
int tab[] = { 5,4,3,2,1 };
iter(tab, 5, print<int>);
return 0;
}

Accept template as function parameter

Could someone explain the difference between the two function calls here?
When can you pass a templated variable to a function?
In both cases I should end up with an templated array inside the function, but only one compiles.
template<int DIM>
struct MyStruct
{
array<int, DIM> structArr;
};
template<int DIM> void testA( MyStruct <DIM>& myStruct) { }
template<int DIM> void testB( array<int, DIM>& arrA) { }
int main()
{
MyStruct<3> myStruct;
array<int, 3> arr;
testA(myStruct);
testB(arr); //compile error
return 0;
}
EDIT:
Error messages look like this:
error: no matching function for call to ‘testB(std::array&)’
testB(arr); //compile error
^
note: candidate: template void testB(std::array&)
template<int DIM> void testB( array<int, DIM>& arrA) { }
^~~~~
note: template argument deduction/substitution failed:
note: mismatched types ‘int’ and ‘long unsigned int’
The template parameter for the size of a std::array is of type std::size_t. However, here you require supplying an int for DIM in the function definition. This is probably an issue for the template deduction rules.

unpacking values of an array as parameters to a variadic function

I am trying (at compile time) to unpack integers as arguments to a variadic function. The idea would be to have those values packed in an array or in a std::index_sequence (c++14) at compile time. I have tried to use some of the answers from older posts, but I find the example code unreadable for my level.
Here is a simple example with the functionality that I need to implement in a code that I am writing, in this case attempting to use std::make_index_sequence. I do not necessarily need to use the latter. The problem is that the values of the sequence are not unpacked as arguments to the variadic function:
#include <cstdio>
#include <iostream>
#include <utility>
using namespace std;
void print(const int &val){
cout << val << endl;
}
template<typename ...S> void print(const int &val, const S&... others)
{
print(val);
print(others...);
}
template<size_t n> void printNumbers(){
std::make_index_sequence<n> a;
print(a);
}
int main(){
printNumbers<6>();
}
The output from GCC8:
tet.cc: In instantiation of ‘void printNumbers() [with long unsigned int n = 6]’:
tet.cc:25:19: required from here
tet.cc:20:8: error: no matching function for call to ‘print(std::make_index_sequence<6>&)’
print(a);
~~~~~^~~
tet.cc:8:6: note: candidate: ‘void print(const int&)’
void print(const int &val){
^~~~~
tet.cc:8:6: note: no known conversion for argument 1 from ‘std::make_index_sequence<6>’ {aka ‘std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5>’} to ‘const int&’
tet.cc:12:30: note: candidate: ‘template<class ... S> void print(const int&, const S& ...)’
template<typename ...S> void print(const int &val, const S&... others)
^~~~~
tet.cc:12:30: note: template argument deduction/substitution failed:
tet.cc:20:9: note: cannot convert ‘a’ (type ‘std::make_index_sequence<6>’ {aka ‘std::integer_sequence<long unsigned int, 0, 1, 2, 3, 4, 5>’}) to type ‘const int&’
std::make_index_sequence<6> is an alias for:
std::integer_sequence<std::size_t, 0, 1, 2, 3, 4, 5>
and this is the type of the expression a that is the argument of the function call print(a). Your print function expects individual values, not an std::integer_sequence.
To make your implementation work, you should first deduce the indices, and only then use them as arguments for print:
template <std::size_t... Is>
void printNumbers(std::index_sequence<Is...>)
{
print(Is...);
}
template <std::size_t N>
void printNumbers()
{
printNumbers(std::make_index_sequence<N>{});
}
In c++17 you could remove the intermediate print function and just say:
template <std::size_t... Is>
void printNumbers(std::index_sequence<Is...>)
{
(print(Is), ...);
}
In c++20 you can both create an index sequence and deduce its indices within a single function:
template <std::size_t N>
void printNumbers()
{
[] <std::size_t... Is> (std::index_sequence<Is...>)
{ (print(Is), ...); }(std::make_index_sequence<N>{});
}
DEMO
As an addendum to the Piotr Skotnicki's answer, I propose a C++14 way to avoid the recursive print().
Not so elegant as the C++17 solution, based on template folding, but equally permit to avoid the use of recursion (and consider that template recursion is usually strict limited by compilers, so the recursive solution works but not when N exceed the recursion limit).
You have to write the printNumber() function as usual, passing a std::make_index_sequence<N> (that inherit from std::index_sequence<0, 1, ...., N-1> aka std::integer_sequence<std::size_t, 0, 1, ..., N-1>) to another function
template <std::size_t N>
void printNumbers ()
{ printNumbers2(std::make_index_sequence<N>{}); }
but in the printNumbers2() you can avoid to call the recursive print() and you can call the print() that effectively call std::cout inside the initialization of an unused array
template <std::size_t ... Is>
void printNumbers2 (std::index_sequence<Is...>)
{
using unused = int[];
(void)unused { 0, (print(Is), 0)... };
}
You can also avoid both print() functions printing directly in printNumbers2()
void printNumbers2 (std::index_sequence<Is...>)
{
using unused = int[];
(void)unused { 0, (std::cout << val << std::endl, 0)... };
}
You can do the same in the C++17/C++20 template folding solutions.
In C++11 this solution doesn't works but only because std::make_integer_sequence and std::index_sequence are introduced from C++11.
If you write a C++11 surrogate for std::make_integer_sequence and std::index_sequence, you can adapt this solution also to C++11.

Differentiate functions when overloading

I'm writing two functions with the same name (and with similar parameters):
The first one only takes a variable amount of integer parameters (minimum one).
The second one takes a variable amount of struct coordinate as parameters (again minimum one).
The struct coordinate can be constructed from both int and std::vector<int>, so the second one can in that way also take int and std::vector<int>.
The problem is that if the first parameter to the second function is an int then the compilation fails.
Is it possible to make the third line in main() call the other tmp function?
My current implementation is listed below.
int main(int argc, char** argv)
{
tmp(1, 2, 3, 4, 5); // OK! First function calls 'single'
tmp(std::vector<int>{1, 2, 3}, 4, 5); // OK! Second function calls 'multi'
tmp(1, std::vector<int>{2, 3}, 4); // Compilation error! First function calls 'single'
return 0;
}
Compiler output:
prog.cpp: In instantiation of ‘std::vector<int> tmp(int, types ...) [with types = {std::vector<int, std::allocator<int> >, int}]’:
prog.cpp:58:34: required from here
prog.cpp:29:23: error: no matching function for call to ‘single(std::vector<int>&, std::vector<int>&, int&)’
single(list, ints ...);
^
prog.cpp:29:23: note: candidates are:
prog.cpp:12:6: note: void single(std::vector<int>&, int)
void single(std::vector<int>& list, int first)
^
prog.cpp:12:6: note: candidate expects 2 arguments, 3 provided
prog.cpp:18:6: note: template<class ... types> void single(std::vector<int>&, int, types ...)
void single(std::vector<int>& list, int first, types ... ints)
^
prog.cpp:18:6: note: template argument deduction/substitution failed:
prog.cpp:29:23: note: cannot convert ‘ints#0’ (type ‘std::vector<int>’) to type ‘int’
single(list, ints ...);
^
My current implementation:
#include <iostream>
#include <vector>
struct coordinate
{
std::vector<int> c;
coordinate(std::vector<int> A) : c(A) {}
coordinate(int A) : c{A} {}
};
// Function to end the recursive call to single
void single(std::vector<int>& list, int first)
{
list.push_back(first);
}
// Recursive function to store the parameters (only int)
template <typename... types>
void single(std::vector<int>& list, int first, types ... ints)
{
list.push_back(first);
single(list, ints ...);
}
// 'First' function
template <typename... types>
std::vector<int> tmp(int i, types ... ints)
{
std::vector<int> list;
list.push_back(i);
single(list, ints ...);
return list;
}
// Function to end the recursive call to multi
void multi(std::vector<std::vector<int> >& list, coordinate first)
{
list.push_back(first.c);
}
// Recursive function for storing the parameters (only 'coordinate')
template <typename... types>
void multi(std::vector<std::vector<int> >& list, coordinate first, types ... coords)
{
list.push_back(first.c);
multi(list, coords ...);
}
// 'Second' function
template <typename... types>
std::vector<std::vector<int> > tmp(coordinate i, types ... coords)
{
std::vector<std::vector<int> > list;
list.push_back(i.c);
multi(list, coords ...);
return list;
}
Alright, based on my new understanding from the comment you want something like this:
template <typename... Args>
typename std::enable_if<all_ints<Args...>::value>::type
tmp(Args... args) {
// the all integer version
}
template <typename... Args>
typename std::enable_if<!all_ints<Args...>::value>::type
tmp(Args... args) {
// the coordinate version
}
Then you just need to write the type trait to check if everything is an integer.
template <typename... T>
struct all_ints : std::true_type { };
template <typename T, typename... Rest>
struct all_ints<T, Rest...>
: std::integral_constant<bool,
std::is_integral<T>::value && all_ints<Rest...>::value>
{ }
I used std::is_integal to handle all the integer types. If you really want explicitly int, you can fix it.

Different template error format in GCC?

GCC has a very verbose format for certain template error messages:
... some_class<A,B,C> [with int A = 1, int B = 2, int C = 3]
Any chance to make it show something like:
... some_class<1,2,3>
You will lose track from what template the specialization comes from:
template<int A, int B> class X {
void f();
};
template<int A> class X<A, 2> {
void f();
};
int main() {
X<1, 2>().f();
X<2, 1>().f();
}
GCC outputs
m.cpp: In function 'int main()':
m.cpp:6:12: error: 'void X<A, 2>::f() [with int A = 1]' is private
m.cpp:10:19: error: within this context
m.cpp:2:12: error: 'void X<A, B>::f() [with int A = 2, int B = 1]' is private
m.cpp:11:19: error: within this context
If it just said X<1, 2> and X<2, 1> you would lose an important information that this diagnostic contains.
No, unless you are willing to maintain a private branch of GCC's source.
Although it is reasonable to want this for class templates, function templates may overload against each other and have different template argument lists for the same function. Then the latter style of error would be ambiguous.
Use the option -fno-pretty-templates. This does what you want, and also omits default template arguments.