访问前 n 个可变参数函数参数

发布于 2024-12-06 15:55:38 字数 397 浏览 0 评论 0原文

我有以下代码:

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

丿*梦醉红颜 2024-12-13 15:55:38

这是可能的,但很复杂。这是一些执行此操作的代码。也许可以消除 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;
}

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;
}
一笔一画续写前缘 2024-12-13 15:55:38

我相信这满足了所有要求:

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

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...);
  }
};
紫南 2024-12-13 15:55:38

这是另一种技术,如果可以至少不具有 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();
    }
  }
};

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();
    }
  }
};
呢古 2024-12-13 15:55:38

首先声明这个实用函数:

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

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)...);
  }
}
何其悲哀 2024-12-13 15:55:38

sz 是一个模板参数,您可以直接在代码中使用它。

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

So要识趣 2024-12-13 15:55:38

以下可以工作:

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 的内容构造数组元素。您可以使用 sizeof...(Args) 获取参数的数量(可以是不超过 N 的任何值)。

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

究竟谁懂我的在乎 2024-12-13 15:55:38

你能利用这样的东西吗?

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 样式的打包参数列表,
  • 使用它的方法必须在右侧具有模板化参数

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
安稳善良 2024-12-13 15:55:38

您需要在保持计数的同时解压参数包,并在函子中执行必要的运行时操作。这应该可以帮助您开始:

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

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;
}
拥抱没勇气 2024-12-13 15:55:38

以下几乎有效(并且对于最后 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;
}

有什么区别?

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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文