Access to the first arguments of a variational function n

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 a constructor that will receive the total number of constructor arguments, and assign the first sz number of arguments to the member variable from v

what I want to do is do it like this: Vec<3> var(1.0,2.0,3.0);

+6
source share
9 answers

It is possible, but difficult. Here is the code that does this. Perhaps you can eliminate the holder type, but I leave this 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]="<<vvdata[0]<<std::endl; std::cout<<"v[1]="<<vvdata[1]<<std::endl; std::cout<<"v[2]="<<vvdata[2]<<std::endl; } 
+1
source

I believe that this meets 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...); } }; 
+1
source

This is another method that is much simpler if it has no parameters at least sz:

 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(); } } }; 
+1
source

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)...); } } 
+1
source

sz is a template argument, you can use it directly in your code.

0
source

Can you use 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 several rules that may limit you:

  • you can have only one template... Args line packed argument list in the template class
  • methods that use it should have template arguments on the right side
0
source

The following may work:

 template <typename T, std::size_t N> struct Foo { T arr[N]; template <typename ...Args> Foo(Args &&... args) : arr{std::forward<Args>(args)...} { } }; 

Using:

 Foo<int, 3> a(1,2,3); 

This allows you to create array elements from everything that is converted to T You can get the number of parameters (which can be no more than N ) using sizeof...(Args) .

0
source

You need to unpack the package of arguments, saving the counter and performing the necessary operation during operation. This should start:

 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; } 
0
source

The following almost work (and for the last N arguments instead of the first, but hey). Maybe someone can help with a compilation 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 understand why this is ambiguous, because 0 is more specialized than N, so it should satisfy partial ordering?!?!?

On the contrary, the following is wonderful.

 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?

0
source

Source: https://habr.com/ru/post/898065/


All Articles