Function with a fixed amount of parameters determined by an integer - c++

I have a class with a template that accepts an integer:
template <unsigned int N>
class Example {};
I'm looking for a way to define a (member)function that accepts some amount of Example objects as arguments. The amount is to be determined by N, so the function would be used like this:
Function(Example<2>(), Example<2>());
Function(Example<3>(), Example<3>(), Example<3>());
What I tried so far:
Using an initializer list, one is able to pass a set of objects to the function:
template <unsigned int N>
void Function(std::initializer_list<Example<N>> list);
//...
Function({Example<2>(), Example<2>()});
However, the problem besides the fact that really only one argument is passed(the list), is that with this method any number of arguments can be used:
Function({Example<2>()});
I also tried using a variadic function:
template <unsigned int N>
void Function(Example<N> e...)
{
va_list args;
va_start(args, e);
//...
}
Function(Example<2>(), Example<2>());
This makes it possible to use real parameters, but the problem of using any number of arguments remains, and it's not possible to know how many arguments were actually passed.

Assuming you want the number of arguments to be deduced from the Example<N> type, and that all Example<I> should share the same such N, a C++17 solution might be
template <unsigned int... I>
auto Function( Example<I>... ) ->
std::enable_if_t<( ( I == sizeof...(I) ) && ... )>
{
// or static_assert() if you always want an error
}

Make Function a variadic template and use std::enable_if_t to constrain your it:
Some IsExample trait can be used to make sure that all arguments are instances of Example
sizeof...(pack) can be used to get the size of the parameter pack
template <unsigned int N, typename... Ts>
auto Function(Ts... xs)
-> std::enable_if_t<(IsExample<Ts>::value && ...)
&& (sizeof...(Ts) == N)>
{
}
live example on wandbox

You should utilize variadic function template with static_assert. Unlike approaches involving enable_if this one will produce a readable error message if incorrect arguments are passed.
template<unsigned int ... I>
void Function(Example<I>... items)
{
static_assert
(
true && (... && (static_cast<unsigned int>(sizeof...(I)) == I))
, "This function accepts N arguments of type Example<N>"
);
}
Online compiler

There are many answers that cover SFINAE friendly based constraints, but I don't like placing my SFINAE in the return value:
template <unsigned int... Is,
std::enable_if_t<( ( Is == sizeof...(Is) ) && ... ), bool> = true
>
void Function( Example<Is>... examples )
{
// code
}
or
template<bool b>
using test_requirement = std::enable_if_t<b, bool>;
template <unsigned int... Is,
test_requirement<( ( Is == sizeof...(Is) ) && ... )> = true
>
void Function( Example<Is>... examples )
{
// code
}

+1 for the Massimiliano Janes's elegant solution.
Unfortunately use folding so works only for C++17.
To test, with C++11/C++14, that all I are equals to sizeof...(I) (and maybe that sizeof...(I) is equal to N, where N is the class template argument), it's enough test that a variadic type, that receive unsigned values, is the same type with a different order of values.
I mean: declaring a trivial struct as
template <std::size_t ... Is>
struct IList;
the test can be
std::is_same<IList<N, sizeof...(Is), Is...>,
IList<sizeof...(Is), Is..., N>>::value
Starting from C++14 it's possible to use std::index_sequence instead of IList.
So Example can be written as
template <unsigned int N>
struct Example
{
template <unsigned int ... Is>
auto Function (Example<Is> ...)
-> typename std::enable_if<
std::is_same<IList<N, sizeof...(Is), Is...>,
IList<sizeof...(Is), Is..., N>>::value>::type
{ /* do something */ }
};
The following is a example of use (but remember to include <type_traits>)
int main()
{
Example<1U> e1;
Example<2U> e2;
// e1.Function(); // error
e1.Function(Example<1>{}); // compile
//e1.Function(Example<1>{}, Example<1>{}); // error
// e2.Function(); // error
//e2.Function(Example<2>{}); // error
e2.Function(Example<2>{}, Example<2>{}); // compile
//e2.Function(Example<2>{}, Example<2>{}, Example<2>{}); // error
}

Related

Definition and Initialization of a tuple whose components are of the same templated class, but with different specialisations

I am new to c++ metaprogramming. I tried to look at other answers, but I was not able to find one that could suit my problem.
Or simply I was not able to apply it to my case.
Here I will post a simplified version of the code, to highlight the main features which I would like to obtain.
What I would like to achieve, is the construction of a std::tuple of dimension N (N known at compile-time),
whose components type is given by a template class, MyType, depending on two parameters M and N.
M is fixed, while the type of the tuple component i is actually MyType<M,i>, for i=0,...,N.
Since I have to define recursively a tuple of these types, I have considered the DefineType template.
// general definition
template<Integer M, Integer N>
struct DefineType
{
using rest = typename DefineType<M, N-1>::type;
using type = decltype(std::tuple_cat(std::declval< std::tuple< MyType<M,N>>>(),
std::declval<rest>() ));
};
// specialization for N=0
template<Integer M>
struct DefineType<M,0>
{
using type = typename std::tuple< MyType<M,0> >;
};
This should produce the following types:
DefineType< M, N=0 >: std::tuple< MyType< M,0 > > ;
DefineType< M, N=1 >: std::tuple< MyType< M,0 >, MyType< M,1 > > ;
DefineType< M, N=2 >: std::tuple< MyType< M,0 >, MyType< M,1 > , MyType< M,2 > > ;
and so on, up to a general N.
Then I would like also to initialize a tuple of this kind, based on something which I call param of type Param. For doing this,
I write a code of this kind:
// general definition
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return std::tuple_cat(std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param) ) ;
}
// specialization for N=0
template<Integer M>
typename DefineType<M,0>::type MyClass(Param param)
{
return std::tuple<MyType<M, 0>>(MyType<M, 0>(param));
}
Finally in the main:
int main()
{
// M and N given
const auto myobject=MyClass<M,N>(param);
}
The code is not compiling, complaining that I am initializing too many times DefineType<M,N>. Basically N does not reach the base-case, with N=0. I do not get why...So for sure the recursive type definition is wrong. But, in addition to this, maybe there are other errors that I do not see. I hope you can help me in understanding how to do this. I apologize, but meta programming is very new (and difficult) to me.
Thank you.
Given the definitions
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return std::tuple_cat(std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param) ) ;
}
template<Integer M>
typename DefineType<M,0>::type MyClass(Param param)
{
return std::tuple<MyType<M, 0>>(MyType<M, 0>(param));
}
what you have is two overloaded distinct function templates. The second is not a "partial specialization" of the first because there is no such thing a function template partial specialization, only class template specializations. (And so the call MyClass<M,N-1>(param) can't possibly match the second template, even if it had been previously declared, since the second one only accepts one template argument, meaning the first template is infinitely recursive.)
One solution could be to use a helper class template:
namespace MyClass_detail {
template<Integer M, Integer N>
struct helper {
static typename DefineType<M,N>::type build(const Param& param)
{
return std::tuple_cat(
std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param));
}
};
template<Integer M>
struct helper<M, 0> {
static typename DefineType<M,0>::type build(const Param& param)
{
return std::tuple<MyType<M, 0>>(MyType<M, 0>(param));
}
};
}
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return MyClass_detail::helper<M,N>::build(Param);
}
Though I would recommend taking advantage of std::make_integer_sequence. (This is a C++14 feature, and I see your question is tagged C++11. If you can't use C++14 or later, a search should turn up some replacement implementations for make_integer_sequence and related tools that can be used in C++11.)
#include <utility>
#include <tuple>
namespace MyClass_detail {
template<Integer M, Integer N, Integer ...Inds>
auto MyClass_helper(const Param &param, std::integer_sequence<Integer, Inds...>)
{
return std::make_tuple(MyType<M, N-Inds>(param)...);
}
}
template<Integer M, Integer N>
auto MyClass(Param param)
{
return MyClass_detail::MyClass_helper<M,N>(
param, std::make_integer_sequence<Integer, N+1>{});
}
// And if DefineType is wanted for other uses:
template<Integer M, Integer N>
using DefineType = decltype(MyClass<M,N>(std::declval<Param>()));
See the full working demo on coliru.
I see two problems in your code.
(1) you say that you want that
DefineType< M, N=2 > is std::tuple< MyType< M,0 >, MyType< M,1 > , MyType< M,2 > >
but writing
using type = decltype(std::tuple_cat(std::declval< std::tuple< MyType<M,N>>>(),
std::declval<rest>() ));
inside DefineType, you get the opposite order; you obtain that
DefineType< M, N=2 > is std::tuple<MyType<M, 2>, MyType<M, 1> , MyType<M, 0>>
If you want the order from zero to N, you have to define, in DefineType, before the rest and then the N element; I mean
using type = decltype(std::tuple_cat(
std::declval<rest>(),
std::declval<std::tuple<MyType<M,N>>>() ));
(2) The recursion for MyClass() function doesn't works because in your recursive version call the same MyClass() ever with two template parameters
template<Integer M, Integer N>
typename DefineType<M,N>::type MyClass(Param param)
{
return std::tuple_cat(std::tuple<MyType<M,N>>(MyType<M,N>(param)),
MyClass<M,N-1>(param) ) ;
} // you call the second parameter .........^^^
// also when N is 1 (and N-1 is 0)
so the base-case (defined with only one template parameter) never matches.
Unfortunately partial template specialization doesn't works for template functions, so you can use partial template specialization of structs (see aschepler's answer) or, if you prefer, SFINAE to enable/disable the two versions of MyClass() according the value of N.
I propose the following solution
// specialization for N == 0
template <Integer M, Integer N>
typename std::enable_if<(N == 0), typename DefineType<M,0>::type>::type
MyClass(Param param)
{ return std::tuple<MyType<M, 0>>(MyType<M, 0>(param)); }
// general definition
template <Integer M, Integer N>
typename std::enable_if<(N > 0u), typename DefineType<M,N>::type>::type
MyClass(Param param)
{
return std::tuple_cat(
MyClass<M,N-1>(param),
std::tuple<MyType<M,N>>(MyType<M,N>(param)) );
}
Observe that now the ground case (N == 0) has two template parameter but is enabled only when N is zero. The other case in enabled only when N > 0.
Observe also that you have to write before the ground case version because it is used by the recursive version.
Observe also that I've switched the order of rest/actual type.
If you can use C++14, so std::make_index_sequence/std::index_sequence, I strongly suggest to avoid recursion and to follow the aschepler's suggestion.
You can also avoid recursion for the DefineType itself using specialization as follows
template <Integer, Integer N, typename = std::make_index_sequence<N+1u>>
struct DefineType;
template <Integer M, Integer N, std::size_t ... Is>
struct DefineType<M, N, std::index_sequence<Is...>>
{ using type = std::tuple<MyType<M, Is>...>; };
The following is a full compiling C++14 example
#include <tuple>
#include <type_traits>
using Integer = std::size_t;
using Param = int;
template <Integer M, Integer N>
struct MyType
{ MyType (Param) {} };
template <Integer, Integer N, typename = std::make_index_sequence<N+1u>>
struct DefineType;
template <Integer M, Integer N, std::size_t ... Is>
struct DefineType<M, N, std::index_sequence<Is...>>
{ using type = std::tuple<MyType<M, Is>...>; };
template <Integer M, Integer N>
std::enable_if_t<(N == 0), typename DefineType<M,0>::type>
MyClass(Param param)
{ return std::tuple<MyType<M, 0>>(MyType<M, 0>(param)); }
// general definition
template <Integer M, Integer N>
std::enable_if_t<(N > 0u), typename DefineType<M,N>::type>
MyClass(Param param)
{
return std::tuple_cat(
MyClass<M,N-1>(param),
std::tuple<MyType<M,N>>(MyType<M,N>(param)) );
}
int main ()
{
using t0 = typename DefineType<42u, 0u>::type;
using u0 = std::tuple<MyType<42u, 0u>>;
using t1 = typename DefineType<42u, 1u>::type;
using u1 = std::tuple<MyType<42u, 0u>, MyType<42u, 1u>>;
using t2 = typename DefineType<42u, 2u>::type;
using u2 = std::tuple<MyType<42u, 0u>, MyType<42u, 1u>, MyType<42u, 2u>>;
static_assert( std::is_same<t0, u0>::value, "!" );
static_assert( std::is_same<t1, u1>::value, "!" );
static_assert( std::is_same<t2, u2>::value, "!" );
auto const myobject = MyClass<42u, 2u>(12);
}

How to specialize template pack?

I have the following code, which tries to convert a binary number (passed as a list of booleans, least-significant first, variable lenght) into a decimal number:
#include <iostream>
using namespace std;
template<typename T>
int bin_to_dec(int multi, T first) {
cout<<"mutli"<<multi<<endl;
return first?multi:0;
}
template<typename T, typename... Args>
int bin_to_dec(int multi, T first, Args... args) {
cout<<"mutli"<<multi<<endl;
return (first?multi:0) + adder(multi*2, args...);
}
template<typename T, typename... Args>
int bin_to_dec(T first, Args... args) {
cout<<"mutli"<<1<<endl;
return (first?1:0) + adder(2, args...);
}
int main()
{
cout<<bin_to_dec(true, true, false, true)<<endl;
}
It works quite well, but I would like to make it possible only for booleans, so when I try something like bin_to_dec(1,2,3) it should not compile. I was trying to use something like
template<bool First, bool... Bools>
but I can't figure out how to go further with that. Any ideas?
The obvious approach is to remove the function from the overload set for all template arguments but bool:
template <typename... T>
std::enable_if_t<variadic_and(std::is_same<T, bool>::value...), int>
bin_to_dec(T... bits) {
// probably delegate to differently named functions as an implementation detail
// ...
}
variadic_and() would be a constexpr function returning true if all its arguments are true:
constexpr bool variadic_and() { return true; }
template <typename... T>
constexpr bool variadic_and(bool v, T... vs) {
return v && variadic_and(vs...);
}
With C++17 variadic_and() would be necessary as parameter packs can be expanded with an operator. For example, the implementation of variadic_and() could look like this:
template <typename... T>
constexpr bool variadic_and(T... vs) { return (vs && ...); }
The same approach could be used directly within std::enable_if_t<...>.
Note: the approaches used above requires that the arguments are deduced as bool, i.e., they pretty much need to be of type bool. Since the function shouldn't be callable with int parameters and these would convert to bool, testing whether the argument type is convertable to bool doesn't seem appropriate. However, it may be reasonable to allow some conversions. If so, a corresponding trait would be used in the first paramter to std::enable_if_t.
Just use a static assert. This works perfectly well:
int bin_to_dec() {
return 0;
}
template<typename T, typename ... Args>
int bin_to_dec(T first, Args ... rest)
{
static_assert(std::is_same<bool, T>::value, "Only valid for bools");
return (first ? 1 : 0) + (bin_to_dec(rest...) << 1);
}
int main()
{
cout<<bin_to_dec(true, true, false, true)<<endl;
cout<<bin_to_dec(1, 2, 3)<<endl; //compile error
}

Function to generate a tuple given a size N and a type T

While trying to reply to this question, I found my self in the need of creating a bunch of parameters for a variadic function on the fly where:
the number of the parameters is not given
the types are all the same, but unknown (even if they must be default constructible)
At runtime, the standard containers and a for loop can be used to do that.
Anyway, I'd like to generate a set of parameters at compile time, so as to be able to forward them to a variadic function.
Because of that, a std::tuple seemed the obvious solution.
Here arose the question: given a size N and a default constructible type T at compile time, how can I write a function to generate a tuple of the given size?
I'm looking for something like this:
auto tup = gen<MyType, N>();
On SO is a notable example of a recursive generator based structs but I was struggling with a function based solution and I've not been able to find it anywhere.
A correctly written forwarding function (a la std::apply) should work with std::array<T, N> and anything else that implements the std::tuple_size/std::get interface. That said,
template<size_t, class T>
using T_ = T;
template<class T, size_t... Is>
auto gen(std::index_sequence<Is...>) { return std::tuple<T_<Is, T>...>{}; }
template<class T, size_t N>
auto gen() { return gen<T>(std::make_index_sequence<N>{}); }
Here is a possible implementation of such a function:
#include<utility>
#include<tuple>
template<typename T>
constexpr auto
params(std::index_sequence<0>) {
return std::tuple<T>{};
}
template<typename T, std::size_t I, std::size_t... O>
constexpr auto
params(std::index_sequence<I, O...>) {
auto tup = std::tuple<T>{ T{} };
auto seq = std::make_index_sequence<sizeof...(O)>{};
return std::tuple_cat(tup, params<T>(seq));
}
template<typename T, std::size_t N>
constexpr auto
gen(std::integral_constant<std::size_t, N>) {
return params<T>(std::make_index_sequence<N>{});
}
int main() {
auto tup = gen<int>(std::integral_constant<std::size_t, 3>{});
static_assert(std::tuple_size<decltype(tup)>::value == 3, "!");
}
For the sake of simplicity, I've used int as a type.
With a small effort, user defined types can be used and the constraint of having them default constructible can be relaxed.

Call sequence of template function for sequence of template parameters

Let's imagine I have several template functions, e.g.:
template <int I> void f();
template <int I> void g();
template <int I> void h();
How can I call sequence of any of these functions for sequence of template parameters?
In other words, I need such behaviour:
{some template magic}<1, 5>(f); // This is pseudocode, I don't need exactly this format of calling.
unrolls into:
f<1>();
f<2>();
f<3>();
f<4>();
f<5>();
And I need the same method to work for every of my functions (not only for f, but for g and h too) without writing big awkward structure for every of these functions.
I can use C++11, and even already implemented in latest development gcc version C++1y/C++14 functionality (http://gcc.gnu.org/projects/cxx1y.html), e.g. polymorphic lambdas.
With C++1y features. Instead of calling the function directly and passing the template argument as, well, a template argument, you can create a lambda that takes a function argument which contains the template argument as part of its type. I.e.
f<42>();
[](std::integral_constant<int, 42> x) { f<x.value>(); }
[](auto x) { f<x.value>(); }
With this idea, we can pass the function template f around, when wrapped into such a polymorphic lambda. That's possible for any kind of overload set, one of the things you can't do with ordinary lambdas.
To call f with a sequence of template arguments, we'll need the common indices classes for the indices expansion trick. Those will be in the C++1y Standard Library. Coliru's clang++ compiler for example still uses an older libstdc++ which doesn't have them AFAIK. But we can write our own:
#include <utility>
using std::integral_constant;
using std::integer_sequence; // C++1y StdLib
using std::make_integer_sequence; // C++1y StdLib
// C++11 implementation of those two C++1y StdLib classes:
/*
template<class T, int...> struct integer_sequence {};
template<class T, int N, int... Is>
struct make_integer_sequence : make_integer_sequence<T, N-1, N-1, Is...> {};
template<class T, int... Is>
struct make_integer_sequence<T, 0, Is...> : integer_sequence<T, Is...> {};
*/
When we write make_integer_sequence<int, 5>, we'll get a type that's derived from integer_sequence<int, 0, 1, 2, 3, 4>. From the latter type, we can deduce the indices:
template<int... Indices> void example(integer_sequence<int, Indices...>);
Inside this function, we have access to the indices as a parameter pack. We'll use the indices to call the lamba / function object f as follows (not the function template f from the question):
f( integral_constant<int, Indices>{} )...
// i.e.
f( integral_constant<int, 0>{} ),
f( integral_constant<int, 1>{} ),
f( integral_constant<int, 2>{} ),
// and so on
Parameter packs can only be expanded in certain contexts. Typically, you'd expand the pack as initializers (e.g. of a dummy array), as the evaluation of those is are guaranteed to be ordered (thanks, Johannes Schaub). Instead of an array, one could use a class type such as
struct expand { constexpr expand(...) {} };
// usage:
expand { pattern... };
A dummy array looks like this:
int expand[] = { pattern... };
(void)expand; // silence compiler warning: `expand` not used
Another tricky part is to deal with functions returning void as the pattern. If we combine a function call with a comma operator, we always get a result
(f(argument), 0) // always has type int and value 0
To break any existing overloaded comma operators, add a void()
(f(argument), void(), 0)
Finally, combine all the above to create magic:
template<int beg, class F, int... Is>
constexpr void magic(F f, integer_sequence<int, Is...>)
{
int expand[] = { (f(integral_constant<int, beg+Is>{}), void(), 0)... };
(void)expand;
}
template<int beg, int end, class F>
constexpr auto magic(F f)
{
// v~~~~~~~v see below (*)
return magic<beg>(f, make_integer_sequence<int, end-beg+1>{});
}
Usage example:
#include <iostream>
template<int N> void f() { std::cout << N << "\n"; }
int main()
{
//magic<1, 5>( [](auto x) { f<decltype(x)::value>(); } );
magic<1, 5>( [](auto x) { f<x.value>(); } );
}
(*) IMHO end-beg+1 is bad practice. There's a reason why the StdLib works with half-open ranges of the form [begin, end): The empty range simply is [begin, begin). With the StdLib using half-open ranges, it might be inconsistent to use closed ranges here. (There's one exception in the StdLib I know of, it has to do with PRNGs and the maximum integer value.)
I'd suggest you'd design your magic interface to take half-open ranges, i.e.
magic<1, 6>( [](auto x) { f<x.value>(); } ); // [1, 6) i.e. {1,2,3,4,5}
with the implementation
template<int beg, int end, class F>
constexpr auto magic(F f)
{
// v~~~~~v
return magic<beg>(f, make_integer_sequence<int, end-beg>{});
}
Note the weird +1 disappears.
Using reified functions and template template arguments:
#include <iostream>
template<int I> class f {
public:
static void call() {
std::cout << I << '\n';
}
};
template<template<int I> class X, int I, int J> class magic {
public:
static void call() {
X<I>::call();
magic::call();
}
};
template<template<int I> class X, int I> class magic<X,I,I> {
public:
static void call() {
X<I>::call();
}
};
int main(int argc, char** argv) {
magic<f,2,6>::call();
return 0;
}

Passing position of variadic template argument

I would like to create a function that takes a variable number of template arguments. Later with these arguments the function should pass their position like this:
template<typename R, typename Args...>
R myFunction(Data &data, void *function) {
auto f = (R (*)(Args...))function;
return f(read<Args1>(data, 1), read<Args2>(data, 2), ...);// <-- This is the problem
}
The given code is of course not compilable. Is there any way to fix it? Is there a way to do it without variadic templates without too much code duplication?
Yes, that is possible:
// we need a compile-time helper to generate indices
template< std::size_t... Ns >
struct indices
{
typedef indices< Ns..., sizeof...( Ns ) > next;
};
template< std::size_t N >
struct make_indices
{
typedef typename make_indices< N - 1 >::type::next type;
};
template<>
struct make_indices< 0 >
{
typedef indices<> type;
};
With these helpers, you need one forwarder for your function like this:
template<typename R, typename... Args, std::size_t... Ns>
R myFunctionImpl(void *Data, void *function, indices<Ns...> ) {
auto f = (R (*)(Args...))function;
return f(read<Args>(Data, Ns + 1)...);// +1 because indices is zero-based
}
template<typename R, typename... Args>
R myFunction(void *Data, void *function) {
return myFunctionImpl< R, Args... >( Data, function, typename make_indices<sizeof...(Args)>::type() );
}
EDIT: How does it work? First, we determine the size of the argument pack Args through sizeof.... make_indices<N>::type then expands into indices<0,1,2,...,N-1>. It is given as an additional parameter to the implementation function (from the forwarder who just creates a dummy instance), hence argument deduction kicks in on the implementation function's side and puts the generated indices into the argument pack Ns.
The implementation function now has two argument packs with the same size, namely Args and Ns. When expanded through the ellipsis ..., the ellipsis expands the whole expression that it's applied to and it expands all parameter packs in parallel! In the above example that expression is read<Args>(Data, Ns+1), which nicely expands into the OPs pseudo-code.