Q: Template specialization with parameter pack - c++

I'll get right to the question.
We have template specialization:
class TestClass
{
public:
template<typename T>
static T fn(const T& a);
}
// OK
template<typename T>
T TestClass::fn(const T& a)
{
// ... magic for any type here ...
}
// OK
template<>
int TestClass::fn(const int& a)
{
// ... magic for int type here ...
}
All okay. But what if I want to add a parameter pack to the function?
class TestClass
{
public:
template<typename T, typename... Args>
static T fn(const T& a, Args&& ...b);
}
// OK
template<typename T, typename... Args>
T TestClass::fn(const T& a, Args&& ...b)
{
// ... magic for any type here ...
}
// Error
template<typename... Args>
int TestClass::fn(const int& a, Args&& ...b)
{
// ... magic for int type here ...
}
Visual Studio gives error E0147.
How can I do this without adding a new function to the class?
Thanks in advance for your help!
Have a nice day!

In your first example
template<>
int TestClass::fn(const int& a)
{ /* ... */ }
you have a full specialization, that is permitted for C++ template functions/methods
But, given the declaration
template<typename T, typename... Args>
static T fn(const T& a, Args&& ...b);
your second example
template<typename... Args>
int TestClass::fn(const int& a, Args&& ...b)
{ /* ... */ }
become a partial specialization, that isn't permitted for C++ functions/methods.
But you can use overloading, avoiding specialization at all, adding a declaration for a different template method with the same name.
I mean
class TestClass
{
public:
template <typename T, typename ... Args>
static T fn (T const & a, Args && ... b);
template <typename ... Args>
static T fn (int const & a, Args && ... b);
};
template <typename T, typename ... Args>
T TestClass::fn (T const & a, Args && ... b)
{ /* ... */ }
template <typename ... Args>
int TestClass::fn (int const & a, Args && ... b)
{ /* ... */ }

Related

Template function for casting multiple number of params

I'm trying to write a template function that will perform a set of dynamic_casts() based on its template parameter. I've got the following to illustrate:
class FooData
{
public:
virtual ~FooData() {};
};
class DerivedFooData: public FooData{};
class Other: public FooData{};
void bar(DerivedFooData* d1, DerivedFooData* d2) {}
void bar(DerivedFooData* d1, Other*, DerivedFooData* d2, Other*, Other*) {}
int main()
{
DerivedFooData d1,d2;
std::vector<FooData*> container1{&d1, &d2};
std::vector<FooData*> container2{&d1, &d2};
// I want bar to be called with container1[0] cast to DerivedFooData and container2[1] cast to DerivedFooData
// the first two template params are each container size
foo<1, 1, DerivedFooData, DerivedFooData>(container, container2);
// I want bar to be called with
// container1[0] cast to DerivedFooData
// container1[1] cast to Other
// container2[0] cast to DerivedFooData
// container2[1] cast to Other
// container2[2] cast to Other
foo<2, 3, DerivedFooData, Other, DerivedFooData, Other, Other>(container, container2);
}
I can manually create some of those:
template <int N, int M, typename U, typename V>
void foo(const std::vector<FooData*>& input, const std::vector<FooData*>& output)
{
bar(dynamic_cast<U*>(input[0]), dynamic_cast<V*>(output[0]));
}
template <int N, int M, typename U, typename V, typename W, typename X, typename Y>
void foo(const std::vector<FooData*>& input, const std::vector<FooData*>& output)
{
bar(dynamic_cast<U*>(input[0]), dynamic_cast<V*>(input[1]), dynamic_cast<W*>(output[0]), dynamic_cast<X*>(output[1]), dynamic_cast<Y*>(output[2]));
}
But I can't figure out how to specify in a generic way all combinations of N and M. I assume variadic templates will come in somewhere, but I would need some guidance.
Not elegant at all (and not sure about the exact indexes) but... something as follows (given that you can use C++14) should works (if I understand correctly what do you want)
template <std::size_t Dim1, typename ... Ts, std::size_t ... Is>
void foo_helper (std::index_sequence<Is...>, std::vector<FooData*> inV,
std::vector<FooData*> outV)
{ bar( dynamic_cast<Ts*>(Is < Dim1 ? inV[Is] : outV[Is-Dim1])... ); }
template <std::size_t Dim1, std::size_t Dim2, typename ... Ts>
void foo (std::vector<FooData*> inV, std::vector<FooData*> outV)
{ foo_helper<Dim1, Ts...>
(std::make_index_sequence<Dim1+Dim2>{}, inV, outV); }
I know that C++20 is too recent for you but, just for fun, I show you how use the new C++20 lambda-template feature to avoid the use of the helper function
// from C++20: foo_helper() isn't needed anymore
template <std::size_t Dim1, std::size_t Dim2, typename ... Ts>
void foo (std::vector<FooData*> inV, std::vector<FooData*> outV)
{ [&]<std::size_t ... Is>(std::index_sequence<Is...>)
{ bar( dynamic_cast<Ts*>(Is < Dim1 ? inV[Is] : outV[Is-Dim1])... ); }
(std::make_index_sequence<Dim1+Dim2>{}); }
The following is a full compiling C++14 example
#include <vector>
#include <type_traits>
struct FooData { virtual ~FooData() {}; };
class DerivedFooData: public FooData { };
class Other : public FooData { };
void bar (DerivedFooData*, DerivedFooData*) {}
void bar (DerivedFooData*, Other*, DerivedFooData*, Other*, Other*) {}
template <std::size_t Dim1, typename ... Ts, std::size_t ... Is>
void foo_helper (std::index_sequence<Is...>, std::vector<FooData*> inV,
std::vector<FooData*> outV)
{ bar( dynamic_cast<Ts*>(Is < Dim1 ? inV[Is] : outV[Is-Dim1])... ); }
template <std::size_t Dim1, std::size_t Dim2, typename ... Ts>
void foo (std::vector<FooData*> inV, std::vector<FooData*> outV)
{ foo_helper<Dim1, Ts...>
(std::make_index_sequence<Dim1+Dim2>{}, inV, outV); }
int main ()
{
DerivedFooData d1, d2, d3;
std::vector<FooData*> container1 {&d1, &d2};
std::vector<FooData*> container2 {&d1, &d2, &d3};
foo<1, 1, DerivedFooData, DerivedFooData>(container1, container2);
foo<2, 3, DerivedFooData, Other, DerivedFooData, Other, Other>
(container1, container2);
}
The basic idea behind any template recursion is to handle the arguments one at a time, recurse on the function with one input type argument removed, and then terminate when the template argument list is empty.
A common way to handle two variadic type lists is to define a "pack" type that you can specialize on, where the pack takes a variable number of template arguments. This gives you the ability to easily separate multiple sets of variadic type arguments.
Here, I demonstrate this example by declaring type_pack without any implementation (which is fine, we only use it as a type and we never instantiate it) and then I declare multiple specializations of foo_fn that are designed to:
Peel the first type off of one of the two lists and perform the dynamic_cast.
Determine the next step by removing the first type argument to the relevant pack type.
Transition to the second pack when the first one becomes empty.
Pass the processed (cast) arguments through to the next step.
Finally, call bar() with the computed arguments when both packs are empty.
template <typename...>
struct type_pack;
// Base declaration that we will specialize.
template <int, int, typename, typename>
struct foo_fn;
// Specialization handling when the first pack is not empty.
template <int OffsetA, int OffsetB, typename THead, typename... T1, typename... T2>
struct foo_fn<OffsetA, OffsetB, type_pack<THead, T1...>, type_pack<T2...>> {
template <typename... Args>
static void f(foovec_t const & input, foovec_t const & output, Args && ... args) {
return foo_fn<
OffsetA + 1,
OffsetB,
type_pack<T1...>,
type_pack<T2...>
>::f(input, output, std::forward<Args>(args)..., dynamic_cast<THead *>(input[OffsetA]));
}
};
// Specialization handling when the first pack is empty and the second
// pack is not empty.
template <int OffsetA, int OffsetB, typename THead, typename... T>
struct foo_fn<OffsetA, OffsetB, type_pack<>, type_pack<THead, T...>> {
template <typename... Args>
static void f(foovec_t const & input, foovec_t const & output, Args && ... args) {
return foo_fn<
OffsetA,
OffsetB + 1,
type_pack<>,
type_pack<T...>
>::f(input, output, std::forward<Args>(args)..., dynamic_cast<THead *>(output[OffsetB]));
}
};
// Specialization handling the terminating case (all packs empty).
template <int OffsetA, int OffsetB>
struct foo_fn<OffsetA, OffsetB, type_pack<>, type_pack<>> {
template <typename... Args>
static void f(foovec_t const &, foovec_t const &, Args && ... args) {
bar(std::forward<Args>(args)...);
}
};
// Helper type to provide the two initial integer values.
template <typename, typename>
struct foo;
template <typename... T1, typename... T2>
struct foo<type_pack<T1...>, type_pack<T2...>> {
static void f(foovec_t const & input, foovec_t const & output) {
foo_fn<0, 0, type_pack<T1...>, type_pack<T2...>>::f(input, output);
}
};
You would call this like foo<type_pack<DerivedFooData, Other>, type_pack<DerivedFooData, Other, Other>>::f(container, container2) in your second example. Note that you don't have to provide any sizes; these are inferred from the size of each pack.
See this demo and note that the pointer arguments where the type doesn't match come through as null.
I don't attempt to define bar() as I assume you have already done this, or know how to do it. The bar() in my example only accepts specific pointer types (for the purposes of testing that the casts were correctly performed).
This code uses only C++11 features.
Note that std::forward is not strictly necessary because the cast values are always pointers. However, it's good to get in the habit of using it when forwarding a variable-size argument list. If the values were huge strings/vectors then forwarding at each step would eliminate a ton of useless copying.
I prefer "pack type" syntax instead of give extra numbers, so
foo<std::tuple<DerivedFooData, Other>, std::tuple<DerivedFooData, Other, Other>>
instead of your:
foo<2, 3, DerivedFooData, Other, DerivedFooData, Other, Other>
You can still do:
template <typename Tuple, std::size_t ... Is1, std::size_t ... Is2, typename ... Ts>
void foo(std::index_sequence<Is1...>, std::index_sequence<Is2...>, Ts&&...args)
{
foo<std::tuple<std::tuple_element_t<Is1, Tuple>...>,
std::tuple<std::tuple_element_t<sizeof...(Is1) + Is2, Tuple>...>>(
std::forward<Ts>(args)...);
}
template <std::size_t N1, std::size_t N2, typename ... Ts>
void foo(const std::vector<FooData*>& input, const std::vector<FooData*>& output)
{
static_assert(N1 + N2 == sizeof...(Ts), "!");
foo<std::tuple<Ts...>>(std::make_index_sequence<N1>{},
std::make_index_sequence<N2>{},
input,
output);
}
to use your syntax.
Now using a primary helper to cast each vector element inside a tuple
template <typename Pack> struct dynamic_cast_as_tuple;
template <typename ...Ts>
struct dynamic_cast_as_tuple<std::tuple<Ts...>>
{
template <typename T>
std::tuple<Ts*...> operator ()(const std::vector<T*>& v) const
{
return (*this)(v, std::index_sequence_for<Ts...>{});
}
private:
template <typename T, std::size_t ... Is>
std::tuple<Ts*...> operator ()(const std::vector<T*>& v, std::index_sequence<Is...>) const
{
return {dynamic_cast<Ts*>(v[Is])...};
}
};
And then, wanted function is:
template <typename pack1, typename pack2>
void foo(const std::vector<FooData*>& input, const std::vector<FooData*>& output)
{
std::apply([](auto*... ps){ bar(ps...); },
std::tuple_cat(
dynamic_cast_as_tuple<pack1>{}(input),
dynamic_cast_as_tuple<pack2>{}(output))
);
}
Demo
std::index_sequence is C++14 and std::apply c++17, but can be implemented in C++11.

Can I specialize a variadic template argument based on the signature of its operator()

Suppose I have a function like this
template <typename... FunctionList>
void call_all (int i, float f, const FunctionList... function_list);
template <>
void call_all (int, float)
{
}
I want to specialize it something like this:
template <typename HasIntArgument, typename... FL>
void call_all (int i, float f, const HasIntArgument & hia, const FL... list)
{
hia (i);
call_all (i, f, list...);
}
template <typename HasFloatArgument, typename... FL>
void call_all (int i, float f, const HasFloatArgument & hfa, const FL... list)
{
hfa (f);
call_all (i, f, list...);
}
In words, I want this function to, for each function-like object in function_list, determine whether it is callable with signature void(int) or void(float). (Nothing in this list will be callable with more than one signature.)
I want this to work with raw function pointers, lambdas, or anything with a suitable operator().
Can I write a suitable specialization directly, or do I have to do weird stuff with traits classes and SFINAE?
You might do something like:
#if 0 // C++17
template <typename F>
void dispatch(F func, int i, float f)
{
if constexpr (has_int_argument<F>::value) {
func(i);
} else {
func(f);
}
}
#else // C++11
template <typename F>
typename std::enable_if<has_int_argument<F>::value>::type
dispatch(F func, int i, float)
{
func(i);
}
template <typename F>
typename std::enable_if<!has_int_argument<F>::value>::type
dispatch(F func, int, float f)
{
func(f);
}
#endif
template <typename... Fs>
void call_all (int i, float f, const Fs&... fs)
{
// (dispatch(fs, i, f), ...); // C++17
const int dummy[] = {0, (dispatch(fs, i, f), 0)...};
static_cast<void>(dummy);
}
With appropriate function traits has_int_argument. something like:
template <typename ClassOrSig> struct funct_trait;
template <typename C>
struct funct_trait : funct_trait<decltype(&C::operator())> {};
template <typename C, typename Ret, typename ...Args>
struct funct_trait<Ret (C::*) (Args...)> : funct_trait<Ret(Args...)> {};
template <typename C, typename Ret, typename ...Args>
struct funct_trait<Ret (C::*) (Args...) const> : funct_trait<Ret(Args...)> {};
// &&, &, volatile, ... (C ellipsis)
template <typename Ret, typename ...Args>
struct funct_trait<Ret (*)(Args...)> : funct_trait<Ret(Args...)> {};
template <typename Ret, typename ...Args>
struct funct_trait<Ret (Args...)>
{
using sig_type = Ret(Args...);
using args_tuple = std::tuple<Args...>;
// ...
};
template <typename T>
using has_int_argument = std::is_same<std::tuple<int>,
typename funct_trait<T>::args_tuple>;
Demo
template<class...Fs>struct overloaded:Fs...{
using Fs::operator()...;
};
template<class...Fs>
overloaded(Fs...)->overloaded<Fs...>;
the above is a bit trickier in c++14, but implementations exist all over the place.
namespace details {
struct secret_tag {};
struct secret_result {
template<class...Ts>
secret_tag operator()(Ts&&...) const;
};
template<class F>
using secret_tester = overloaded<std::decay_t<F>, secret_result>;
}
template<class F, class Arg>
using match_arg_exactly = std::integral_constant<
bool,
!std::is_same<
details::secret_tag,
std::result_of_t< details::secret_tester<F>(Arg) >
>{}
>;
now we can ask for a given object if it can match a specific argument exactly.
template <typename HasIntArgument>
void call_one(int i, float f, std::true_type, const HasIntArgument & hia)
{
hia (i);
}
template <typename HasFloatArgument>
void call_one(int i, float f, std::false_type, const HasFloatArgument& hia)
{
hia (f);
}
template <typename F>
void call_one(int i, float f, const F & hia)
{
call_one( i, f, match_arg_exactly<const F&, int>{}, hia );
}
and we use this:
void call_all (int, float)
{}
template<class F, class...Fs>
void call_all (int i, float f, F const& f0, Fs const&...fs) {
call_one( i, f, f0 );
call_all(i, f, fs...);
}
Test code:
struct float_eater {
void operator()(float x)const{ std::cout<< "float "<<x<<"\n"; }
};
struct int_eater {
void operator()(int x)const{ std::cout<< "int "<<x<<"\n"; }
};
call_all( 42, 3.14, float_eater{}, int_eater{}, int_eater{} );
Live example
A c++14 overloaded is something like:
template<class...Fs>
struct overloaded;
template<class F0>
struct overloaded<F0>:F0 {
overloaded(F0 f0):F0(std::move(f0)) {}
using F0::operator();
};
template<class F0, class F1>
struct overloaded<F0, F1>: F0, F1 {
overloaded( F0 f0, F1 f1 ):F0(std::move(f0)), F1(std::move(f1)) {}
using F0::operator();
using F1::operator();
};
template<class F0, class...Fs>
struct overloaded<F0, Fs...>:
overloaded<F0, overloaded<Fs...>>
{
overloaded(F0 f0, Fs...fs):
F0(std::move(f0)),
overloaded<Fs...>( std::move(fs)... )
{}
};
which I think is sufficient for our purposes. (More generally, you either make a binary tree, balanced or not), and handle perfect forwarding, and... etc.

Variadic C++ Templates Termination After Unpack?

I'm trying to use C++ variadic templates to unpack a list of arguments of variable type, how would I remove the "T" object in the following artificial example:
struct Test
{
template <typename T, typename... Args>
void foo(T t, int i, Args... args) { foo(t, args...); }
template <typename T, typename... Args>
void foo(T t, double d, Args... args) { foo(t, args...); }
template <typename T>
void foo(T t) { }
};
struct DummyObject { };
and then executed like this:
DummyObject dummy;
Test test;
test.foo(dummy, 4, 5.0, 6, 7.0, 8.0, 9);
I'd like to remove the need to pass in the "dummy" object at all, I just can't figure out what the final "foo" function should look like in this case.
Let me flesh out your sample slightly:
struct Test
{
template <typename T, typename... Args>
void foo(T t, int i, Args... args) { doIThing(i); foo(t, args...); }
template <typename T, typename... Args>
void foo(T t, double d, Args... args) { doDThing(d); foo(t, args...); }
template <typename T>
void foo(T t) { }
};
So there's the two functions that do actual work: doIThing and doDThing. You got it 99% right, just... remove T.
struct Test
{
template <typename... Args>
void foo(int i, Args... args) { doIThing(i); foo(args...); }
template <typename... Args>
void foo(double d, Args... args) { doDThing(d); foo(args...); }
void foo() { }
};
Running here: http://coliru.stacked-crooked.com/a/b35ac716cf2960b3
Other method is to remove recursive call and have something like:
struct Test
{
template <typename... Args>
void foos(Args... args)
{
(foo(args), ...); // C++17 fold expression
#if 0 // C++11 or C++14
const int dummy[] = {0, (foo(args), 0)...};
static_cast<void>(dummy); // avoid warning for unused variable
#endif
}
void foo(int t) { /*...*/ }
void foo(double t) { /*...*/ }
template <typename t> void foo(T t) { /**/ }
};
And then use it:
Test test;
test.foos(4, 5.0, 6, 7.0, 8.0, 9);

Passing vector items to function-object with unknown number of parameters

Here is a simplified version of what I am trying to achieve:
template <class Func, class Params>
void foo(Func f, Params p) {
f(p[0], p[1], ...) // <-- this is the problem. How to do this?
}
...
foo([](int a, int b){ cout<<(a+b); }, std::vector<int>{1,2});
foo([](char a){ cout<<a; }, std::vector<char>{'a'});
I hope the problem is clear.
EDIT:
The above example did not convey the problem well. I have a vector, populated at some earlier stage, of the parameters. I want a function that will accept a function-object and call it with the parameters from the vector. I can assume that the vector size is equal to the number of parameters.
Hopefully better example:
class C {
std::vector<int> v;
public:
void add_param(int);
... // other functions that manipulate the vector in various ways
template<class Func>
void run(Func f) {
f(v[0], etc...); // <-- problem
}
};
You can use variardic templates:
template <class Func, class... Params>
void foo(Func f, Params... p) {
f(p...);
}
foo([](int a, int b){ cout<<(a+b); }, 1, 2);
foo([](char a){ cout<<a; }, 'a');
You may use something like:
// Minimal traits to have information about function
template <typename Func> struct function_traits;
template <typename Ret, typename ... Ts>
struct function_traits<Ret (Ts...)>
{
constexpr static auto arity = sizeof...(Ts);
};
template <typename Ret, typename ... Ts>
struct function_traits<Ret (*)(Ts...)> : function_traits<Ret(Ts...)> {};
template <typename C, typename Ret, typename ... Ts>
struct function_traits<Ret (C::*)(Ts...) const> : function_traits<Ret(Ts...)> {};
template <typename C>
struct function_traits : function_traits<decltype(&C::operator())> {};
namespace detail
{
template <typename F, typename Vec, std::size_t ... Is>
void call(const F& f, Vec&& v, std::index_sequence<Is...>)
{
f(v[Is]...);
}
}
template <class Func, class Vec>
void foo(const Func& f, Vec&& v) {
detail::call(f,
std::forward<Vec>(v),
std::make_index_sequence<function_traits<Func>::arity>());
}
Demo

accessing first n variadic function arguments

I have the following code :
template<size_t sz,typename T=float> class Vec{
T v[sz];
Vec(const T& val,const T&... nv){
//how do i assign `sz` number of first arguments into `this->v` array
}
}
I want to create constructor, that receive generic number of constructor argument, and assign the first sz number of arguments into member variable of v
what I want to do, is to be able doing like this: Vec<3> var(1.0,2.0,3.0);
This is possible, but complicated. Here is some code that does it. It may be possible to eliminate the holder type, but I leave that as an exercise for the reader. This has been tested with g++ 4.6.
#include <iostream>
#include <typeinfo>
template<size_t ... Indices> struct indices_holder
{};
template<size_t index_to_add,typename Indices=indices_holder<> >
struct make_indices_impl;
template<size_t index_to_add,size_t...existing_indices>
struct make_indices_impl<index_to_add,indices_holder<existing_indices...> >
{
typedef typename make_indices_impl<
index_to_add-1,
indices_holder<index_to_add-1,existing_indices...> >::type type;
};
template<size_t... existing_indices>
struct make_indices_impl<0,indices_holder<existing_indices...> >
{
typedef indices_holder<existing_indices...> type;
};
template<size_t max_index>
typename make_indices_impl<max_index>::type make_indices()
{
return typename make_indices_impl<max_index>::type();
}
template<unsigned index,typename ... U>
struct select_nth_type;
template<unsigned index,typename T,typename ... U>
struct select_nth_type<index,T,U...>
{
typedef typename select_nth_type<index-1,U...>::type type;
static type&& forward(T&&,U&&... u)
{
return select_nth_type<index-1,U...>::forward(static_cast<U&&>(u)...);
}
};
template<typename T,typename ... U>
struct select_nth_type<0,T,U...>
{
typedef T type;
static type&& forward(T&&t,U&&...)
{
return static_cast<T&&>(t);
}
};
template<unsigned index,typename ... U>
typename select_nth_type<index,U...>::type&& forward_nth(U&&... u)
{
return static_cast<typename select_nth_type<index,U...>::type&&>(
select_nth_type<index,U...>::forward(
static_cast<U&&>(u)...));
}
template<size_t sz,typename T=float> struct Vec{
struct holder
{
T data[sz];
};
holder v;
template<typename ... U>
struct assign_helper
{
template<size_t... Indices>
static holder create_array(indices_holder<Indices...>,Vec* self,U&&... u)
{
holder res={{static_cast<T>(forward_nth<Indices>(u...))...}};
return res;
}
};
template<typename ... U>
Vec(U&&... u):
v(assign_helper<U...>::create_array(make_indices<sz>(),this,static_cast<U&&>(u)...))
{}
};
int main()
{
Vec<3> v(1.2,2.3,3.4,4.5,5.6,7.8);
std::cout<<"v[0]="<<v.v.data[0]<<std::endl;
std::cout<<"v[1]="<<v.v.data[1]<<std::endl;
std::cout<<"v[2]="<<v.v.data[2]<<std::endl;
}
I believe this satisfies all the requirements:
template <size_t sz,typename T,typename... Args> struct Assign;
template <typename T,typename First,typename...Rest>
struct Assign<1,T,First,Rest...> {
static void assign(T *v,const First &first,const Rest&... args)
{
*v = first;
}
};
template <size_t sz,typename T,typename First,typename... Rest>
struct Assign<sz,T,First,Rest...> {
static void assign(T *v,const First &first,const Rest&... rest)
{
*v = first;
Assign<sz-1,T,Rest...>::assign(v+1,rest...);
}
};
template<size_t sz,typename T=float>
struct Vec{
T v[sz];
template <typename... Args>
Vec(const T& val,const Args&... nv){
Assign<sz,T,T,Args...>::assign(v,val,nv...);
}
};
This is another technique which is much simpler if it is ok not to have at least sz parameters:
template<size_t sz,typename T=float>
struct Vec {
T v[sz];
template <typename... Args>
Vec(const T& val,const Args&... nv)
{
T data[] = {val,static_cast<const T &>(nv)...};
int i=0;
for (; i<sz && i<(sizeof data)/sizeof(T); ++i) {
v[i] = data[i];
}
for (; i<sz; ++i) {
v[i] = T();
}
}
};
First declare this utility function:
template <typename T> inline void push(T* p) {}
template <typename T, typename First, typename... Args>
inline void push(T* p, First&& first, Args&&... args)
{
*p = first;
push(++p, std::forward<Args>(args)...);
}
Then, in your class:
template<size_t sz,typename T=float>
class Vec
{
T v[sz];
template <typename... Args>
Vec(T first, Args&&... args) // << we have changed const T& to T&&
{
//how do i assign `sz` number of first arguments into `this->v` array
// like this:
push(&v[0], first, std::forward<Args>(args)...);
}
}
sz is a template argument, you can directly use it in your code.
The following could work:
template <typename T, std::size_t N>
struct Foo
{
T arr[N];
template <typename ...Args> Foo(Args &&... args) : arr{std::forward<Args>(args)...} { }
};
Usage:
Foo<int, 3> a(1,2,3);
This allows you to construct the array elements from anything that's convertible to T. You can obtain the number of parameters (which can be anything not exceeding N) with sizeof...(Args).
Can you make use of something like this?
template <typename... Args> class Vec {
std :: tuple <Args...> m_args;
Vec (const Foo & a, const Bar & b, Args&&... args)
: m_args (args...)
{
// ... something with a, b
}
};
There are a few rules to constrain you:
you can only have one template... Args-style packed argument list per template class
methods which use it must have the templated arguments on the right-hand-side
You need to unpack the argument pack while keeping a count and do the necessary runtime operation in a functor. This should get you started:
template<unsigned, typename...>
struct unroll;
template<unsigned size, typename Head, typename... Tail>
struct unroll<size, Head, Tail...> {
void operator()(Head&& h, Tail&&... tail) {
// do your stuff, pass necessary arguments through the ctor of the
// struct
unroll<size - 1, Tail...>()(std::forward<Tail>(tail)...);
}
};
template<typename Head, typename... Tail>
struct unroll<1, Head, Tail...> {
void operator()(Head&& h, Tail&&... tail) {
// do your stuff the last time and do not recurse further
}
};
int main()
{
unroll<3, int, double, int>()(1, 3.0, 2);
return 0;
}
The following almost works (and for the last N arguments instead of the first, but hey). Perhaps someone can help with the compile error in the comments below:
#include <iostream>
void foo (int a, int b) {
std :: cout << "3 args: " << a << " " << b << "\n";
}
void foo (int a, int b, int c) {
std :: cout << "3 args: " << a << " " << b << " " << c << "\n";
}
template <int n, typename... Args>
struct CallFooWithout;
template <typename... Args>
struct CallFooWithout <0, Args...> {
static void call (Args... args)
{
foo (args...);
}
};
template <int N, typename T, typename... Args>
struct CallFooWithout <N, T, Args...> {
static void call (T, Args... args)
{
CallFooWithout <N-1, Args...> :: call (args...);
// ambiguous class template instantiation for 'struct CallFooWithout<0, int, int, int>'
// candidates are: struct CallFooWithout<0, Args ...>
// struct CallFooWithout<N, T, Args ...>
}
};
template <int n, typename... Args>
void call_foo_with_last (Args... args)
{
CallFooWithout <sizeof...(Args)-n, Args...> :: call (args...);
}
int main ()
{
call_foo_with_last <2> (101, 102, 103, 104, 105);
call_foo_with_last <3> (101, 102, 103, 104, 105);
}
I don't see why it's ambiguous because 0 is more specialised than N so that should satisfy the partial order ?!?!?
By contrast, the below is fine.
template <int N, typename... T>
struct Factorial
{
enum { value = N * Factorial<N - 1,T...>::value };
};
template <typename... T>
struct Factorial<0, T...>
{
enum { value = 1 };
};
void foo()
{
int x = Factorial<4,int>::value;
}
What's the difference?