доступ к первым n аргументам переменной функции - PullRequest
6 голосов
/ 26 сентября 2011

У меня есть следующий код:

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
    }
}

Я хочу создать конструктор, который получит общий номер аргумента конструктора, и назначить первое sz количество аргументов в переменную-член v

то, что я хочу сделать, это уметь делать так: Vec<3> var(1.0,2.0,3.0);

Ответы [ 9 ]

1 голос
/ 01 октября 2011

Это еще один метод, который намного проще, если не нужно иметь хотя бы 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 голос
/ 03 февраля 2012

Сначала объявите эту служебную функцию:

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

Затем в вашем классе:

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 голос
/ 26 сентября 2011

Это возможно, но сложно.Вот код, который это делает.Может быть возможно устранить тип holder, но я оставляю это как упражнение для читателяЭто было проверено с 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;
}
1 голос
/ 01 октября 2011

Я считаю, что это удовлетворяет всем требованиям:

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...);
  }
};
0 голосов
/ 28 сентября 2011

Следующие почти работают (и для last N аргументов вместо первого, но эй).Возможно, кто-то может помочь с ошибкой компиляции в комментариях ниже:

#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);
}

Я не понимаю, почему это неоднозначно, потому что 0 более специализирован, чем N, поэтому должен удовлетворять частичному порядку?!?!?

В отличие от этого, все в порядке.

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

В чем разница?

0 голосов
/ 26 сентября 2011

Вам нужно распаковать пакет аргументов, сохраняя при этом счетчик, и выполнить необходимую операцию времени выполнения в функторе.Это должно начать вас:

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 голосов
/ 26 сентября 2011

Может работать следующее:

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

Использование:

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

Это позволяет создавать элементы массива из всего, что может быть преобразовано в T.Вы можете получить количество параметров (которое может быть любым, не превышающим N) с помощью sizeof...(Args).

0 голосов
/ 26 сентября 2011

Можете ли вы использовать что-то подобное?

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

Есть несколько правил, которые могут вас ограничить:

  • вы можете иметь только один упакованный стиль template... Argsсписок аргументов для каждого шаблона класса
  • методы, которые его используют, должны иметь шаблонные аргументы справа
0 голосов
/ 26 сентября 2011

sz - это аргумент шаблона, вы можете напрямую использовать его в своем коде.

...