The following code compiles:
#include "List.h"
//namespace prototypeInd{namespace templates{ //Uncomment for error
template <size_t N, typename Lambda>
inline void static_for(const Lambda& f,std::integral_constant<size_t,N>) {
static_for(f, std::integral_constant<size_t,N-1>());
f(std::integral_constant<size_t,N-1>());
}
template <typename Lambda>
inline void static_for(const Lambda& f, std::integral_constant<size_t,1>) {
f(std::integral_constant<size_t,0>());
}
//}} //Uncomment for error
//using namespace prototypeInd::templates; //Uncomment for error
template<size_t N>
using ic = std::integral_constant<size_t,N>;
typedef List<ic<0>,ic<1>,ic<2>,ic<3>,ic<4>,ic<5>,ic<6>,ic<7> > list;
int main(int argc,char** args){
static_for([](auto i){ std::cout << list::IndexOf<i>() << std::endl; },list::SizeOf());
}
But as soon as you uncomment the marked lines it gives a huge whopper of an error.
Here is List.h:
template<class First, class... Rest>
struct SizeOf_ : std::integral_constant<size_t, SizeOf_<Rest...>() + 1>{};
template<class First>
struct SizeOf_<First> : std::integral_constant<size_t,1> { };
template<size_t index, class First, class... Rest>
struct Index_{
static_assert(index < SizeOf_<First,Rest...>(), "Index is outside of bounds");
typedef typename Index_<index - 1, Rest...>::value value;
};
template<class First, class... Rest>
struct Index_<0,First, Rest...>{
typedef First value;
};
template<class First_t, class... Rest_t>
struct List{
template<size_t i>
using IndexOf = typename Index_<i,First_t,Rest_t...>::value;
typedef SizeOf_<First_t, Rest_t...> SizeOf;
};
This seems inexplicable....A namespace should not change the function of the code?!?!?!? (or should it?).
I am using g++ with std=c++14....Any help is appreciated
Why does having a namespace change anything?
When Alf compiles this code with g++ 5.1.0 and removes the out-commenting, that compiler reports as first error that
foo.cpp:11:5: error: static assertion failed: Index is outside of bounds
static_assert(index < SizeOf_<First,Rest...>(), "Index is outside of bounds");
The complete diagnostics avalanche for that first error:
foo.cpp: In instantiation of 'struct Index_<18446744073709551615ull, std::integral_constant<long long unsigned int, 0ull>, std::integral_constant<long long unsigned int, 1ull>, std::integral_constant<long long unsigned int, 2ull>, std::integral_constant<long long unsigned int, 3ull>, std::integral_constant<long long unsigned int, 4ull>, std::integral_constant<long long unsigned int, 5ull>, std::integral_constant<long long unsigned int, 6ull>, std::integral_constant<long long unsigned int, 7ull> >':
foo.cpp:21:64: required by substitution of 'template<class First_t, class ... Rest_t> template<long long unsigned int i> using IndexOf = typename Index_<i, First_t, Rest_t ...>::value [with long long unsigned int i = i; First_t = std::integral_constant<long long unsigned int, 0ull>; Rest_t = {std::integral_constant<long long unsigned int, 1ull>, std::integral_constant<long long unsigned int, 2ull>, std::integral_constant<long long unsigned int, 3ull>, std::integral_constant<long long unsigned int, 4ull>, std::integral_constant<long long unsigned int, 5ull>, std::integral_constant<long long unsigned int, 6ull>, std::integral_constant<long long unsigned int, 7ull>}]'
foo.cpp:52:38: required from 'main(int, char**):: [with auto:1 = std::integral_constant<long long unsigned int, 18446744073709551615ull>]'
foo.cpp:33:15: recursively required from 'void prototypeInd::templates::static_for(const Lambda&, std::integral_constant<long long unsigned int, N>) [with long long unsigned int N = 7ull; Lambda = main(int, char**)::]'
foo.cpp:33:15: required from 'void prototypeInd::templates::static_for(const Lambda&, std::integral_constant<long long unsigned int, N>) [with long long unsigned int N = 8ull; Lambda = main(int, char**)::]'
foo.cpp:52:90: required from here
foo.cpp:11:5: error: static assertion failed: Index is outside of bounds
static_assert(index < SizeOf_<First,Rest...>(), "Index is outside of bounds");
^
Related
Here is a snippet from my code:
template <typename Type, unsigned int NumberOfRows, unsigned int NumberOfColumns>
class HexMatrix
{
private:
std::array<Type, NumberOfRows*NumberOfColumns> values;
// ...
public:
template <typename... OtherType>
HexMatrix(OtherType...);
// ...
};
template <typename Type, unsigned int NumberOfRows, unsigned int NumberOfColumns>
template <typename... OtherType>
HexMatrix<Type, NumberOfRows, NumberOfColumns>::HexMatrix(OtherType... args) : values({ args... })
{
static_assert(NumberOfRows != 0u);
static_assert(NumberOfColumns != 0u);
}
Until recently, I was able to use this code as is, and initialise the std::array with an std::vector using the constructor above. Then my PC got formatted. Now this doesn't compile anymore, even though I was using and am still using -std=c++2a. Here is the compilation report:
In file included from foo.cpp:3:
LinearAlgebra.hpp: In instantiation of ‘HexMatrix< <template-parameter-1-1>, <anonymous>, <anonymous> >::HexMatrix(OtherType ...) [with OtherType = {std::vector<long double, std::allocator<long double> >}; Type = long double; unsigned int NumberOfRows = 6; unsigned int NumberOfColumns = 6]’:
LinearAlgebra.hpp:230:9: required from ‘static HexMatrix<Type, NumberOfRows, NumberOfColumns> HexMatrix< <template-parameter-1-1>, <anonymous>, <anonymous> >::Make(OtherType ...) [with OtherType = {std::vector<long double, std::allocator<long double> >}; Type = long double; unsigned int NumberOfRows = 6; unsigned int NumberOfColumns = 6]’
foo.cpp:93:80: required from here
LinearAlgebra.hpp:299:98: error: no matching function for call to ‘std::array<long double, 36>::array(<brace-enclosed initializer list>)’
299 | HexMatrix<Type, NumberOfRows, NumberOfColumns>::HexMatrix(OtherType... args) : values({ args... })
| ^
In file included from /usr/include/c++/9/tuple:39,
from /usr/include/c++/9/bits/hashtable_policy.h:34,
from /usr/include/c++/9/bits/hashtable.h:35,
from /usr/include/c++/9/unordered_map:46,
from Using.hpp:5,
from LinearAlgebra.hpp:4,
from foo.cpp:3:
/usr/include/c++/9/array:94:12: note: candidate: ‘std::array<long double, 36>::array()’
94 | struct array
| ^~~~~
/usr/include/c++/9/array:94:12: note: candidate expects 0 arguments, 1 provided
/usr/include/c++/9/array:94:12: note: candidate: ‘constexpr std::array<long double, 36>::array(const std::array<long double, 36>&)’
/usr/include/c++/9/array:94:12: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘const std::array<long double, 36>&’
/usr/include/c++/9/array:94:12: note: candidate: ‘constexpr std::array<long double, 36>::array(std::array<long double, 36>&&)’
/usr/include/c++/9/array:94:12: note: no known conversion for argument 1 from ‘<brace-enclosed initializer list>’ to ‘std::array<long double, 36>&&’
make: *** [Makefile:16: foo.o] Error 1
What's wrong? I tried to remove the parenthesis, and/or add another pair of brackets around args... but that didn't change anything. Please help?
Reproductible example:
int main(void)
{
const std::vector<long double> foo = { 1.L, 2.L, -6.L, 0.L };
HexMatrix<long double, 2u, 2u> givenMatrix(foo);
return 0;
}
If you want to pass a vector in the constructor, add a new constructor to HexMatrix:
#include <vector>
#include <array>
#include <algorithm>
template <typename Type, unsigned int NumberOfRows, unsigned int NumberOfColumns>
class HexMatrix
{
private:
std::array<Type, NumberOfRows*NumberOfColumns> values;
// ...
public:
template <typename... OtherType>
HexMatrix(OtherType...);
HexMatrix(const std::vector<Type>&);
// ...
};
template <typename Type, unsigned int NumberOfRows, unsigned int NumberOfColumns>
template <typename... OtherType>
HexMatrix<Type, NumberOfRows, NumberOfColumns>::HexMatrix(OtherType... args) : values({ args... })
{
static_assert(NumberOfRows != 0u);
static_assert(NumberOfColumns != 0u);
}
template <typename Type, unsigned int NumberOfRows, unsigned int NumberOfColumns>
HexMatrix<Type, NumberOfRows, NumberOfColumns>::HexMatrix(const std::vector<Type>& vec)
{
static_assert(NumberOfRows != 0u);
static_assert(NumberOfColumns != 0u);
std::copy_n(vec.begin(), NumberOfRows*NumberOfColumns, values.begin());
}
int main(void)
{
const std::vector<long double> foo = { 1.L, 2.L, -6.L, 0.L };
HexMatrix<long double, 2u, 2u> givenMatrix(foo);
return 0;
}
I have the following code that iterates through the types of a std::tuple and concatenates their names as strings.
#include <type_traits>
#include <tuple>
#include <string>
template<typename types_T, int n, typename T>
concept tuple_element_is = (std::is_same<typename std::tuple_element<n, types_T>::type, T>::value);
template<typename types_T, int n>
requires tuple_element_is<types_T, n, float>
constexpr const std::string foo() {
if constexpr (n < std::tuple_size<types_T>::value - 1) {
return "float" + foo<types_T, n + 1>();
} else {
return "float";
}
}
template<typename types_T, int n>
requires tuple_element_is<types_T, n, int>
constexpr const std::string foo() {
if constexpr (n < std::tuple_size<types_T>::value - 1) {
return "int" + foo<types_T, n + 1>();
} else {
return "int";
}
}
auto t0 = foo<std::tuple<int>, 0>();
auto t1 = foo<std::tuple<float>, 0>();
auto t2 = foo<std::tuple<int, int>, 0>();
auto t3 = foo<std::tuple<int, float>, 0>();
//auto t4 = foo<std::tuple<float, int>, 0>(); -- does not compile
auto t5 = foo<std::tuple<float, float>, 0>();
auto t6 = foo<std::tuple<int, int, int>, 0>();
auto t7 = foo<std::tuple<int, int, float>, 0>();
//auto t8 = foo<std::tuple<int, float, int>, 0>(); -- does not compile
auto t9 = foo<std::tuple<int, float, float>, 0>();
//auto t10 = foo<std::tuple<float, int, int>, 0>(); -- does not compile
//auto t11 = foo<std::tuple<float, int, float>, 0>(); -- does not compile
//auto t12 = foo<std::tuple<float, float, int>, 0>(); -- does not compile
auto t13 = foo<std::tuple<float, float, float>, 0>();
The instantiation t4, t8, t10, t11, t12 do not compile and produced this error:
note: template argument deduction/substitution failed:
note: constraints not satisfied
In substitution of ‘template<class types_T, int n> requires tuple_element_is<types_T, n, float> constexpr const string foo() [with types_T = std::tuple<float, int>; int n = 1]’:
required from ‘constexpr const string foo() [with types_T = std::tuple<float, int>; int n = 0; std::string = std::__cxx11::basic_string<char>]’
required from here
required for the satisfaction of ‘tuple_element_is<types_T, n, float>’ [with types_T = std::tuple<float, int>; n = 1]
note: the expression ‘std::is_same<typename std::tuple_element<(long unsigned int)n, types_T>::type, T>::value [with n = 1; types_T = std::tuple<float, int>; T = float]’ evaluated to ‘false’
The last note is interesting, because it is true that this expression evaluates to false, but he used the float variant for the second call.
Maybe I'm using it wrong, but the compiler should re-check the requirements for each recursive call of foo and select the correct substitution, in this case int.
More interestingly, it works the other way around for t3, t7
Note that calling foo<std::tuple<float, int>, 1>(); directly also works.
I have tested it with both GCC and clang and they produce the same result.
Any idea?
Clang gives me a very straightforward error message:
error: call to function 'foo' that is neither visible in the template definition nor found by argument-dependent lookup
return "float" + foo<types_T, n + 1>();
^
note: in instantiation of function template specialization 'foo<std::tuple<float, int>, 0>' requested here
auto t4 = foo<std::tuple<float, int>, 0>(); //-- does not compile
^
note: 'foo' should be declared prior to the call site
constexpr const std::string foo() {
The int variant of foo is not visible in the float variant, and "should be declared prior to the call site". In other words, it should be forward-declared, like this:
template<typename types_T, int n>
requires tuple_element_is<types_T, n, int>
constexpr const std::string foo();
Demo
GCC's error message is a little harder to understand, but it's still relatively straightforward when you're used to template related error messages:
error: no matching function for call to 'foo<std::tuple<float, int>, (0 + 1)>()'
12 | return "float" + foo<types_T, n + 1>();
| ~~~~~~~~~~~~~~~~~~~^~
note: candidate: 'template<class types_T, int n> requires tuple_element_is<types_T, n, float> constexpr const std::string foo()'
10 | constexpr const std::string foo() {
It doesn't mention any other candidate, meaning that it only considers the one it can see: the first one. Again, because the second one is not declared by that point.
I would like a function bool dominates(const std::tuple<T...>& t1, const std::tuple<T...>& t2) which returns true iff tuple t1 dominates tuple t2, i.e. for all i, t1[i] <= t2[i], in contrast with the default <= operator which uses a lexicographic comparison.
I've tried to adapt the answer from this question, but without success. It fails at compilation.
template<typename H>
bool& dominates_impl(bool& b, H&& h1, H&& h2)
{
b &= std::forward<H>(h1) <= std::forward<H>(h2);
return b;
}
template<typename H, typename... T>
bool& dominates_impl(bool& b, H&& h1, H&& h2, T&&... t1, T&&... t2)
{
b &= (std::forward<H>(h1) <= std::forward<H>(h2));
return dominates_impl(b, std::forward<T>(t1)..., std::forward<T>(t2)...);
}
template<typename... T, std::size_t... I>
bool dominates(
const std::tuple<T...>& t1,
const std::tuple<T...>& t2,
integer_sequence<std::size_t, I...>)
{
bool b = true;
int ctx[] = { (dominates_impl(b, std::get<I>(t1)..., std::get<I>(t2)...), 0), 0};
(void)ctx;
return b;
}
template <typename ... T>
bool dominates(
const std::tuple<T...>& t1,
const std::tuple<T...>& t2)
{
return dominates(t1, t2, gen_indices<sizeof...(T)>{});
}
Compilation errors:
./common.hpp: In instantiation of 'bool dominates(const std::tuple<_Tps ...>&, const std::tuple<_Tps ...>&, integer_sequence<long unsigned int, I ...>) [with T = {long int, long int, long int, long int, long int}; long unsigned int ...I = {0, 1, 2, 3, 4}]':
./common.hpp:107:21: required from 'bool dominates(const std::tuple<_Tps ...>&, const std::tuple<_Tps ...>&) [with T = {long int, long int, long int, long int, long int}]'
examples.cpp:1624:65: required from here
./common.hpp:97:34: error: no matching function for call to 'dominates_impl(bool&, std::__tuple_element_t<0, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<1, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<2, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<3, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<4, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<0, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<1, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<2, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<3, std::tuple<long int, long int, long int, long int, long int> >&, std::__tuple_element_t<4, std::tuple<long int, long int, long int, long int, long int> >&)'
97 | int ctx[] = { (dominates_impl(b, std::get<I>(t1)..., std::get<I>(t2)...), 0), 0};
| ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./common.hpp:77:7: note: candidate: 'template<class H> bool& dominates_impl(bool&, H&&, H&&)'
77 | bool& dominates_impl(bool& b, H&& h1, H&& h2)
| ^~~~~~~~~~~~~~
./common.hpp:77:7: note: template argument deduction/substitution failed:
./common.hpp:97:34: note: candidate expects 3 arguments, 11 provided
97 | int ctx[] = { (dominates_impl(b, std::get<I>(t1)..., std::get<I>(t2)...), 0), 0};
| ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
./common.hpp:84:7: note: candidate: 'bool& dominates_impl(bool&, H&&, H&&, T&& ..., T&& ...) [with H = const long int&; T = {const long int&, const long int&, const long int&, const long int&, const long int&, const long int&, const long int&, const long int&}]'
84 | bool& dominates_impl(bool& b, H&& h1, H&& h2, T&&... t1, T&&... t2)
| ^~~~~~~~~~~~~~
./common.hpp:84:7: note: candidate expects 19 arguments, 11 provided
The problem in you code is in dominates_impl()
template<typename H, typename... T>
bool& dominates_impl(bool& b, H&& h1, H&& h2, T&&... t1, T&&... t2)
you can't have two variadic argument list of argument in a function; you can have only one in last position.
But you don't need dominates_impl() at all: you can emulate C++17 template folding writing dominates() (the three argument version) as follows
template<typename... T, std::size_t... I>
bool dominates(
const std::tuple<T...>& t1,
const std::tuple<T...>& t2,
integer_sequence<std::size_t, I...>)
{
using unused = bool[];
bool b { true };
(void)unused { b, (b = b && std::get<I>(t1) <= std::get<I>(t2))... };
return b;
}
Remember to recover integer_sequence and gen_indices() from the original question.
I was able to make it work in C++11, but only by manually reinventing C++14's std::integer_sequence, and losing constexpr-ability:
#include <tuple>
#include <type_traits>
#include <assert.h>
template<typename T, T ...i> struct integer_sequence {};
template<typename T, T v=0>
struct counter {
static constexpr T n=v;
typedef counter<T, v-1> prev;
};
template<typename T, typename V, T ...i> struct integer_sequence_impl;
template<typename T, T ...i>
struct integer_sequence_impl<T, counter<T>, i...> {
typedef struct integer_sequence<T, 0, i...> t;
};
template<typename T, typename V, T ...i> struct integer_sequence_impl
: integer_sequence_impl<T, typename V::prev, V::n, i...> {};
template<typename T, T n>
using create_integer_sequence=
typename integer_sequence_impl<T, counter<T, n-1>>::t;
template<class T, T N>
using make_integer_sequence=create_integer_sequence<T, N>;
template<typename T1,
typename T2,
std::size_t ...i>
bool dominates_impl(const T1 &t1,
const T2 &t2,
const integer_sequence<std::size_t, i...> &)
{
bool compare[]={
(std::get<i>(t1) <= std::get<i>(t2))...
};
for (auto f:compare)
if (!f)
return false;
return true;
}
template<typename ...T1,
typename ...T2,
typename=typename std::enable_if<sizeof...(T1) == sizeof...(T2)>::type>
bool dominates(const std::tuple<T1...> &t1,
const std::tuple<T2...> &t2)
{
return dominates_impl(t1, t2,
make_integer_sequence<std::size_t, sizeof...(T1)>
{});
}
int main()
{
assert(!dominates(std::tuple<int, int>{4, 2},
std::tuple<int, int>{3, 1}));
assert(dominates(std::tuple<int, int>{2, 2},
std::tuple<int, int>{3, 2}));
return 0;
}
A good chunk of the above is a half-baked std::integer_sequence. With that, and C++17's fold expressions this becomes a no-brainer:
#include <tuple>
#include <type_traits>
template<typename T1,
typename T2,
std::size_t ...i>
constexpr bool dominates_impl(const T1 &t1,
const T2 &t2,
const std::integer_sequence<std::size_t, i...> &)
{
return ( (std::get<i>(t1) <= std::get<i>(t2)) && ...);
}
template<typename ...T1,
typename ...T2,
typename=std::enable_if_t<sizeof...(T1) == sizeof...(T2)>>
constexpr bool dominates(const std::tuple<T1...> &t1,
const std::tuple<T2...> &t2)
{
return dominates_impl(t1, t2,
std::make_index_sequence<sizeof...(T1)>{});
}
static_assert(!dominates(std::tuple{4, 2},
std::tuple{3, 1}));
static_assert(dominates(std::tuple{2, 2},
std::tuple{3, 2}));
This program defines a simple container for an array of std::unique_ptr<unsigned int>.
#include <memory>
#include <array>
#include <type_traits>
template <unsigned int dim>
class container {
template <std::size_t... I>
container(std::array<unsigned int, dim> Ls, std::index_sequence<I...>) : container(std::get<I>(Ls)...) { }
public:
const std::array<std::unique_ptr<unsigned int>, dim> data;
template <typename... UInts, class = std::enable_if_t<(sizeof...(UInts) == dim) && (std::is_same_v<UInts, unsigned int> && ...)>>
container(UInts... Ls) : data{ std::make_unique<unsigned int>(Ls)...} { }
template <typename Indices = std::make_index_sequence<dim>>
container(std::array<unsigned int, dim> Ls) : container(Ls, Indices{}) { }
};
int main()
{
unsigned int x = 1;
unsigned int y = 2;
container<2> a({x,y});
return 0;
}
The compilation with gcc 8.2.1 fails however, with the following error.
$ g++ -Wall -pedantic -std=c++17 -o test test.cpp
test.cpp: In function ‘int main()’:
test.cpp:25:23: error: call of overloaded ‘container(<brace-enclosed initializer list>)’ is ambiguous
container<2> a({x,y});
^
test.cpp:17:3: note: candidate: ‘container<dim>::container(std::array<unsigned int, dim>) [with Indices = std::integer_sequence<long unsigned int, 0, 1>; unsigned int dim = 2]’
container(std::array<unsigned int, dim> Ls) : container(Ls, Indices{}) { }
^~~~~~~~~
test.cpp:6:7: note: candidate: ‘container<2>::container(const container<2>&)’ <deleted>
class container {
^~~~~~~~~
test.cpp:6:7: note: candidate: ‘container<2>::container(container<2>&&)’ <deleted>
make: *** [Makefile:3: test] Error 1
Indeed, the copy constructor is deleted because of the presence of the array of std::unique_ptr (but still participates to the overload resolution).
Strangely, on gcc 7.3.0 the above code compiles with no errors or warnings.
Also, defining a simplified container, having a copyable array of unsigned int, as in the following program, no error occurs with both gcc 8.2.1 and gcc 7.3.0
#include <array>
#include <type_traits>
template <unsigned int dim>
class container_simple {
template <std::size_t... I>
container_simple(std::array<unsigned int, dim> Ls, std::index_sequence<I...>) : container_simple(std::get<I>(Ls)...) { }
public:
const std::array<unsigned int, dim> data;
template <typename... UInts, class = std::enable_if_t<(sizeof...(UInts) == dim) && (std::is_same_v<UInts, unsigned int> && ...)>>
container_simple(UInts... Ls) : data{ Ls...} { }
template <typename Indices = std::make_index_sequence<dim>>
container_simple(std::array<unsigned int, dim> Ls) : container_simple(Ls, Indices{}) { }
};
int main()
{
unsigned int x = 1;
unsigned int y = 2;
container_simple<2> a({x,y});
return 0;
}
Is it a compiler bug? If not, where is the ambiguity?
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...>();
}