member function implementation depending on template parameter - c++

I have the following problem:
template< typename T, size_t N, size_t... N_i >
class A
{
public:
// ...
// first implementation
template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M!=1, size_t >::type = 0 >
A<T, N_i...> operator[]( size_t i )
{
A< T, N_i... > res{ ... };
return res;
}
// second implementation
template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M==1, size_t >::type = 0 >
T operator[]( size_t i )
{
return ... ;
}
};
As you can see above, I try to implement a class A which expects as template arguments a type T (e.g. int or float) and sizeof...(N_i)+1-many size_t.
Dependent on the number of passed size_t (i.e. sizeof...(N_i)+1), I will use a different implementation for the member function operator[](size_t) with a different result type:
one implementation for the case sizeof...(N_i)+1 > 1 with return type A < T, N_i... >
(referred to as "first implementation" in the code)
and one for the case sizeof...(N_i)+1 == 1 with return type T
(referred to as "second implementation" in the code).
Unfortunately, I have no idea how this can be implemented -- the solution above does not work. Has anyone an idea?
Many thanks in advance.

A<T, N_i...> is invalid for empty N_i.
As workaround, you may use indirection:
template <typename, std::size_t ...>
struct PopFrontA
{
using type = void; // Dummy type for A<T, N>
};
template< typename T, std::size_t N, std::size_t... N_i > class A;
template <typename T, std::size_t N, std::size_t N2, std::size_t ... Ns>
struct PopFrontA<T, N, N2, Ns...>
{
using type = A<T, N2, Ns...>;
};
template <typename T, std::size_t ... Ns>
using PopFrontA_t = typename PopFrontA<T, Ns...>::type;
And then
// first implementation
template< size_t M = sizeof...(N_i)+1, typename std::enable_if< M!=1, size_t >::type = 0 >
PopFrontA_t<T, N, N_i...>
operator[]( size_t i )
{
A< T, N_i... > res{ /*...*/ };
return res;
}
Demo

If you modify
A< T, N_i... > res{ ... };
in
A< T, N_i... > res{ };
and
return ... ;
in
return T{} ;
isn't enough?
--- EDIT ---
No: as pointed by Jarod42 (thanks!), isn't enough.
So I propose the following solution, based on class template specialization and std::conditional to avoid the use of SFINAE
#include <iostream>
#include <type_traits>
template< typename, size_t...>
class A;
template< typename T, size_t N, size_t... N_i >
class A<T, N, N_i...>
{
public:
template <typename Next = typename std::conditional<sizeof...(N_i),
A<T, N_i...>, T>::type>
Next operator[] (size_t i)
{ return Next{}; }
};
int main(int argc, char* argv[])
{
A<int, 2, 4> a;
std::cout << a[1][2] << std::endl;
return 0;
}
If you don't want specialize A, you can add a sub-struct of A to do the dirty work.
#include <iostream>
#include <type_traits>
template< typename T, size_t N, size_t... N_i >
class A
{
template <typename U, size_t ... O_i>
struct Next
{ using type = A<U, O_i...>; };
template <typename U>
struct Next<U>
{ using type = U; };
public:
using next_t = typename Next<T, N_i...>::type;
next_t operator[] (size_t i)
{ return next_t{}; }
};
int main(int argc, char* argv[])
{
A<int, 2, 4> a;
std::cout << a[1][2] << std::endl;
return 0;
}

Related

class instantiation in nested classes

I have the following problem:
template< typename T, size_t N, size_t... N_i >
struct A
{
// nested class
template< typename... Ts >
class B
{
//...
A<T, N_i...>::B< Ts... > operator[]( size_t i )
{
A< T, N_i...>::B< Ts... > res{ /* ... */ };
return res;
}
// ...
};
};
Unfortunately, the compiler yields an error for "A < T, N_i...>::B < Ts... > res{ /* ... */ };". Does anyone know how I can return an instantiation of the class B (which differs in its template arguments of his outer class A) in the function "operator[]" of class B?
Many thanks in advance.
Should be enough add a typename before A<T, N_i...> and a template before B< Ts... >.
I mean
template< typename T, size_t N, size_t... N_i >
struct A
{
// nested class
template< typename... Ts >
class B
{
//...
typename A<T, N_i...>::template B< Ts... > operator[]( size_t i )
{
typename A< T, N_i...>::template B< Ts... > res{ /* ... */ };
return res;
}
// ...
};
}
P.s.: should work also with C++11; not only with C++14
Putting a typename before the full type of the return types is what fixes the errors you're getting. However, don't put the template parameters after the B as B always refers to the "current" instantiation of the type.
#include <stdio.h>
using namespace std;
template< typename T, size_t N, size_t... N_i >
struct A
{
// nested class
template< typename... Ts >
class B
{
//...
typename A<T, N_i...>::B operator[]( size_t i )
{
typename A< T, N_i...>::B res{ /* ... */ };
return res;
}
// ...
};
};
https://godbolt.org/g/hsB4pW

Expand a type N times in template parameter

I have the following problem:
template< std::size_t N >
class A
{
std::function< std::size_t( /*std::size_t,....,std::size_t <- N-times*/) > foo;
};
As you can see above, I try to declare an std::function<...> foo as a member of a class A. Here, I want foo to have the return type std::size_t (which is no problem) and as input, I will pass N-times the type std::size_t but I don't know how. Is there any possibility?
Many thanks in advance.
You can use std::index_sequence:
template<std::size_t N, typename = std::make_index_sequence<N>>
struct A;
template<std::size_t N, std::size_t... S>
struct A<N, std::index_sequence<S...>> {
std::function<std::size_t(decltype(S)...)> foo;
};
Live example
If you like, you could also define to what type it expands:
template<typename T, std::size_t N, typename = std::make_index_sequence<N>>
struct A;
template<typename T, std::size_t N, std::size_t... S>
struct A<T, N, std::index_sequence<S...>> {
template<std::size_t>
using type = T;
std::function<std::size_t(type<S>...)> foo;
};
For arbitrary type and not just size_t, just write a helper alias:
template<class T, size_t>
using Type = T;
template<std::size_t... S>
struct AHelper<std::index_sequence<S...>> {
std::function<size_t(Type<MyArbitraryTypeHere, S>...)> foo;
};
Ok this was fun. Here is my solution:
namespace details {
template <size_t N, class F = size_t()>
struct Function_type_helper {};
template <size_t N, class... Args>
struct Function_type_helper<N, size_t(Args...)> {
using Type = typename Function_type_helper<N - 1, size_t(Args..., size_t)>::Type;
};
template <class... Args>
struct Function_type_helper<0, size_t(Args...)> {
using Type = size_t(Args...);
};
template <size_t N, class F = size_t()>
using Function_type_helper_t = typename Function_type_helper<N, F>::Type;
static_assert(std::is_same_v<Function_type_helper_t<3>, size_t(size_t, size_t, size_t)>);
} // ns details
template<size_t N>
struct A
{
std::function<details::Function_type_helper_t<N>> foo;
};
This works by recursively creating the type size_t(size_t, size_t, ..., size_t)
For instance:
H<3>::Type == H<3, size_t()>::Type ==
H<2, size_t(size_t)>::Type ==
H<1, size_t(size_t, size_t)>::Type ==
H<0, size_t(size_t, size_t, size_t)>::Type ==
size_t(size_t, size_t, size_t)

Recursive variadic template terminated by std::tuple_size in C++11

I have problem with implementing recursive template (function in template struct), which will be terminated by std::tuple_size.
Here is fragment of code (I simplified code, to emphasize problem):
template<int index, typename ...T_arguments>
struct Helper
{
static void func (size_t& return_size,
const std::tuple<T_arguments...>& arguments)
{
const auto& argument (std::get<index> (arguments));
return_size += ::value_size (argument);
::Helper<index + 1, T_arguments...>::func (return_size, arguments);
}
// ...
template<typename... T_arguments>
struct Helper<std::tuple_size<T_arguments...>::value, T_arguments...>
{
static void func (size_t& return_size,
const std::tuple<T_arguments...>& arguments)
{
const auto& argument (std::get<std::tuple_size<T_arguments...>::value> (arguments));
return_size += ::value_size (argument);
}
Initial template call looks like this:
Helper<0, T_arguments...>::func (return_size, arguments);
GCC fails with error:
error: template argument ‘std::tuple_size::value’
involves template parameter(s)
struct Helper::value, T_arguments...>
std::tuple_size is claimed to be known at compile time, so why I cannot use it template specialization?
Actually what you're doing is forbidden by section §14.5.4/9 which says,
A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.
Following may help:
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
total_value_size(size_t& return_size, const std::tuple<Tp...>& t)
{ }
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
total_value_size(size_t& return_size, const std::tuple<Tp...>& t)
{
const auto& argument (std::get<I> (t));
return_size += ::value_size(argument);
total_value_size<I + 1, Tp...>(return_size, t);
}
Use index_sequence and range-based-for.
#include <cstdlib>
#include <cstddef>
#include <tuple>
namespace mpl
{
template< std::size_t ... I>
struct index_sequence
{
};
template< std::size_t s, typename I1, typename I2>
struct concate;
template< std::size_t s, std::size_t ...I, std::size_t ...J>
struct concate<s, index_sequence<I...>, index_sequence<J...> >
{
typedef index_sequence<I... ,( J + s)... > type;
};
template< std::size_t N>
struct make_index_sequence
{
typedef typename concate< N/2,
typename make_index_sequence< N/2>::type,
typename make_index_sequence< N - N/2>::type
>::type type;
};
template<>struct make_index_sequence<0>
{
typedef index_sequence<> type;
};
template<> struct make_index_sequence<1>
{
typedef index_sequence<0> type;
};
template< typename ...T>
struct index_sequence_for
{
typedef typename make_index_sequence< sizeof...(T) > ::type type;
};
} // mpl
template< typename T >
std::size_t value_size( T ){ return sizeof(T); }// only for illustration
template< typename ...Tp, std::size_t ...i>
std::size_t total_value_size_impl( const std::tuple<Tp...> & t, mpl::index_sequence<i...> )
{
std::size_t result=0;
for(auto x: { value_size( std::get<i>(t) ) ... } )
{
result += x;
}
return result;
}
template< typename ...Tp>
std::size_t total_value_size( const std::tuple<Tp...> & t)
{
typedef typename mpl::index_sequence_for<Tp...> :: type indexes;
return total_value_size_impl( t, indexes{} );
}
#include <cstdio>
int main()
{
typedef std::tuple<int, char, double> types;
std::size_t result = total_value_size(types{});
printf("%d\n", result);
}

Non-type variadic function templates in C++11

I saw a blog post which used non-type variadic templates (currently not supported by gcc, only by clang).
template <class T, size_t... Dimensions>
struct MultiDimArray { /* ... */ };
The example in the post compiles fine but I failed to get it to work with function templates.
Can anyone help figuring out the correct syntax (if such exists)?
int max(int n) { return n; } // end condition
template <int... N> // replacing int... with typename... works
int max(int n, N... rest) // !! error: unknown type name 'N'
{
int tmp = max(rest...);
return n < tmp? tmp : n;
}
#include <iostream>
int main()
{
std::cout << max(3, 1, 4, 2, 5, 0) << std::endl;
}
This will print out all elements,
get max could be implemented similarly
template <int N>
void foo(){
cout << N << endl;
}
template <int N, int M, int ... Rest>
void foo(){
cout << N << endl;
foo<M, Rest...>();
}
int main(){
foo<1, 5, 7>();
return 0;
}
You are simply confusing type names and non-type names. What you want simply doesn’t work.
You can probably use variadic non-type templates in functions, but not as (non-template) arguments:
template <int N, int... Rest>
int max()
{
int tmp = max<Rest...>();
return N < tmp ? tmp : N;
}
std::cout << max<3, 1, 4, 2, 5, 0>() << std::endl;
… although I haven’t tested this and I’m not sure how this should work given that you need to have a partial specialisation as the base case. You could solve this by dispatching to a partially specialised struct:
template <int N, int... Rest>
struct max_t {
static int const value = max_t<Rest...>::value > N ? max_t<Rest...>::value : N;
};
template <int N>
struct max_t<N> {
static int const value = N;
};
template <int... NS>
int max()
{
return max_t<NS...>::value;
}
This will work.
Here are two ways of defining a variadic function template only accepting int parameters. The first one generates a hard-error when instantiated, the second uses SFINAE:
template<typename... T>
struct and_: std::true_type {};
template<typename First, typename... Rest>
struct and_
: std::integral_constant<
bool
, First::value && and_<Rest...>::value
> {};
template<typename... T>
void
foo(T... t)
{
static_assert(
and_<std::is_same<T, int>...>::value
, "Invalid parameter was passed" );
// ...
}
template<
typename... T
, typename = typename std::enable_if<
and_<std::is_same<T, int>...>::value
>::type
>
void
foo(T... t)
{
// ...
}
As you can see, non-type template parameters aren't used here.
Luc Danton's solution doesn't behave correctly with parameters which are not of type int, but can be implicitly converted to an int. Here's one which does:
template<typename T, typename U> struct first_type { typedef T type; };
template<typename T> int max_checked(T n) { return n; }
template<typename T1, typename T2, typename ...Ts>
int max_checked(T1 n1, T2 n2, Ts ...ns)
{
int maxRest = max_checked(n2, ns...);
return n1 > maxRest ? n1 : maxRest;
}
template<typename ...T> auto max(T &&...t) ->
decltype(max_checked<typename first_type<int, T>::type...>(t...))
{
return max_checked<typename first_type<int, T>::type...>(t...);
}
struct S { operator int() { return 3; } };
int v = max(1, 2.0, S()); // v = 3.
Here, max forwards all arguments unchanged to max_checked, which takes the same number of arguments of type int (provided by performing a pack-expansion on the first_type template). The decltype(...) return type is used to apply SFINAE if any argument can't be converted to int.
Here's how you could achieve variadic args in your max example such that it can take any number of arithmetic arguments:
template<typename T, typename ... Ts>
struct are_arithmetic{
enum {
value = std::is_arithmetic<T>::value && are_arithmetic<Ts...>::value
};
};
template<typename T>
struct are_arithmetic<T>{
enum {
value = std::is_arithmetic<T>::value
};
};
template<typename Arg, typename = typename std::enable_if<std::is_arithmetic<Arg>::value>::type>
Arg max(Arg arg){
return arg;
}
template<typename Arg, typename Arg1, typename ... Args, typename = typename std::enable_if<are_arithmetic<Arg, Arg1, Args...>::value>::type>
auto max(Arg arg, Arg1 arg1, Args ... args){
auto max_rest = max(arg1, args...);
return arg > max_rest ? arg : max_rest;
}
int main(){
auto res = max(1.0, 2, 3.0f, 5, 7l);
}
This is good because it can take any numeric type and will return the maximum number by its original type rather than just int, too.

split variadic template arguments

How do I split variadic template arguments in two halves? Something like:
template <int d> struct a {
std::array <int, d> p, q;
template <typename ... T> a (T ... t) : p ({half of t...}), q ({other half of t...}) {}
};
Luc's solution is clean and straightforward, but sorely lacks fun.
Because there is only one proper way to use variadic templates and it is to abuse them to do crazy overcomplicated metaprogramming stuff :)
Like this :
template <class T, size_t... Indx, class... Ts>
std::array<T, sizeof...(Indx)>
split_array_range_imp(pack_indices<Indx...> pi, Ts... ts)
{
return std::array<T, sizeof...(Indx)>{get<Indx>(ts...)...}; //TADA
}
template <class T, size_t begin, size_t end, class... Ts>
std::array<T, end - begin>
split_array_range(Ts... ts)
{
typename make_pack_indices<end, begin>::type indices;
return split_array_range_imp<T>(indices, ts...);
}
template <size_t N>
struct DoubleArray
{
std::array <int, N> p, q;
template <typename ... Ts>
DoubleArray (Ts ... ts) :
p( split_array_range<int, 0 , sizeof...(Ts) / 2 >(ts...) ),
q( split_array_range<int, sizeof...(Ts) / 2, sizeof...(Ts) >(ts...) )
{
}
};
int main()
{
DoubleArray<3> mya{1, 2, 3, 4, 5, 6};
std::cout << mya.p[0] << "\n" << mya.p[1] << "\n" << mya.p[2] << std::endl;
std::cout << mya.q[0] << "\n" << mya.q[1] << "\n" << mya.q[2] << std::endl;
}
It is quite short, except that we need to code some helper :
First we need the structure make_pack_indices, which is used to generate a range of integer at compile-time. For example make_pack_indices<5, 0>::type is actually the type pack_indices<0, 1, 2, 3, 4>
template <size_t...>
struct pack_indices {};
template <size_t Sp, class IntPack, size_t Ep>
struct make_indices_imp;
template <size_t Sp, size_t ... Indices, size_t Ep>
struct make_indices_imp<Sp, pack_indices<Indices...>, Ep>
{
typedef typename make_indices_imp<Sp+1, pack_indices<Indices..., Sp>, Ep>::type type;
};
template <size_t Ep, size_t ... Indices>
struct make_indices_imp<Ep, pack_indices<Indices...>, Ep>
{
typedef pack_indices<Indices...> type;
};
template <size_t Ep, size_t Sp = 0>
struct make_pack_indices
{
static_assert(Sp <= Ep, "__make_tuple_indices input error");
typedef typename make_indices_imp<Sp, pack_indices<>, Ep>::type type;
};
We also need a get() function, very similar to std::get for tuple, such as std::get<N>(ts...) return the Nth element of a parameters pack.
template <class R, size_t Ip, size_t Ij, class... Tp>
struct Get_impl
{
static R& dispatch(Tp...);
};
template<class R, size_t Ip, size_t Jp, class Head, class... Tp>
struct Get_impl<R, Ip, Jp, Head, Tp...>
{
static R& dispatch(Head& h, Tp&... tps)
{
return Get_impl<R, Ip, Jp + 1, Tp...>::dispatch(tps...);
}
};
template<size_t Ip, class Head, class... Tp>
struct Get_impl<Head, Ip, Ip, Head, Tp...>
{
static Head& dispatch(Head& h, Tp&... tps)
{
return h;
}
};
template <size_t Ip, class ... Tp>
typename pack_element<Ip, Tp...>::type&
get(Tp&... tps)
{
return Get_impl<typename pack_element<Ip, Tp...>::type, Ip, 0, Tp...>::dispatch(tps...);
}
But to build get() we also need a pack_element helper structure, again very similar to std::tuple_element, such as pack_element<N, Ts...>::type is the Nth type of the parameters pack.
template <size_t _Ip, class _Tp>
class pack_element_imp;
template <class ..._Tp>
struct pack_types {};
template <size_t Ip>
class pack_element_imp<Ip, pack_types<> >
{
public:
static_assert(Ip == 0, "tuple_element index out of range");
static_assert(Ip != 0, "tuple_element index out of range");
};
template <class Hp, class ...Tp>
class pack_element_imp<0, pack_types<Hp, Tp...> >
{
public:
typedef Hp type;
};
template <size_t Ip, class Hp, class ...Tp>
class pack_element_imp<Ip, pack_types<Hp, Tp...> >
{
public:
typedef typename pack_element_imp<Ip-1, pack_types<Tp...> >::type type;
};
template <size_t Ip, class ...Tp>
class pack_element
{
public:
typedef typename pack_element_imp<Ip, pack_types<Tp...> >::type type;
};
And here we go.
Actually I don't really understand why pack_element and get() are not in the standard library already. Those helpers are present for std::tuple, why not for parameters pack ?
Note : My implementation of pack_element and make_pack_indices is a direct transposition of std::tuple_element and __make_tuple_indices implementation found in libc++.
We still lack a lot of helpers to manipulate variadic parameter packs (or I am not aware of them). Until a nice Boost library brings them to us, we can still write our own.
For example, if you are willing to postpone your array's initialization to the constructor body, you can create and use a function that copies part of the parameter pack to an output iterator:
#include <array>
#include <cassert>
#include <iostream>
// Copy n values from the parameter pack to an output iterator
template < typename OutputIterator >
void copy_n( size_t n, OutputIterator )
{
assert ( n == 0 );
}
template < typename OutputIterator, typename T, typename... Args >
void copy_n( size_t n, OutputIterator out, const T & value, Args... args )
{
if ( n > 0 )
{
*out = value;
copy_n( n - 1, ++out, args... );
}
}
// Copy n values from the parameter pack to an output iterator, starting at
// the "beginth" element
template < typename OutputIterator >
void copy_range( size_t begin, size_t size, OutputIterator out )
{
assert( size == 0 );
}
template < typename OutputIterator, typename T, typename... Args >
void copy_range( size_t begin, size_t size, OutputIterator out, T value, Args... args )
{
if ( begin == 0 )
{
copy_n( size, out, value, args... );
}
else
{
copy_range( begin - 1, size, out, args... );
}
}
template < int N >
struct DoubleArray
{
std::array< int, N > p;
std::array< int, N > q;
template < typename... Args >
DoubleArray ( Args... args )
{
copy_range( 0, N, p.begin(), args... );
copy_range( N, N, q.begin(), args... );
}
};
int main()
{
DoubleArray<3> mya(1, 2, 3, 4, 5, 6);
std::cout << mya.p[0] << mya.p[2] << std::endl; // 13
std::cout << mya.q[0] << mya.q[2] << std::endl; // 46
}
As you can see, you can (not so) easily create your own algorithms to manipulate parameter packs; all is needed is a good understanding of recursion and pattern matching (as always when doing Template MetaProgramming).
Note that in this particular case, you may use std::initializer_list:
template<int... Is> struct index_sequence{};
template<int N, int... Is> struct make_index_sequence
{
typedef typename make_index_sequence<N - 1, N - 1, Is...>::type type;
};
template<int... Is> struct make_index_sequence<0, Is...>
{
typedef index_sequence<Is...> type;
};
template <int d> struct a {
std::array <int, d> p, q;
constexpr a (const std::initializer_list<int>& t) :
a(t, typename make_index_sequence<d>::type())
{}
private:
template <int... Is>
constexpr a(const std::initializer_list<int>& t, index_sequence<Is...>) :
p ({{(*(t.begin() + Is))...}}),
q ({{(*(t.begin() + d + Is))...}})
{}
};
Here is yet another solution:
#include <array>
#include <tuple>
#include <iostream>
template <int i, int o> struct cpyarr_ {
template < typename T, typename L > static void f (T const& t, L &l) {
l[i-1] = std::get<i-1+o> (t);
cpyarr_<i-1,o>::f (t,l);
}
};
template <int o> struct cpyarr_ <0,o> {
template < typename T, typename L > static void f (T const&, L&) {}
};
template <int i, int o, typename U, typename ... T> std::array < U, i > cpyarr (U u, T... t) {
std::tuple < U, T... > l { u, t... };
std::array < U, i > a;
cpyarr_<i,o>::f (l, a); // because std::copy uses call to memmov which is not optimized away (at least with g++ 4.6)
return a;
}
template <int d> struct a {
std::array <int, d> p, q;
template <typename ... T> a (T ... t) : p (cpyarr<d,0> (t...)), q (cpyarr<d,d> (t...)) {}
};
int main () {
a <5> x { 0,1,2,3,4,5,6,7,8,9 };
for (int i = 0; i < 5; i++)
std::cout << x.p[i] << " " << x.q[i] << "\n";
}
I know this question is quite old, but I found it only yesterday while looking for a solution to a very similar problem. I worked out a solution myself and ended up writing a small library which I believe does what you want. You can find a description here if you are still interested.