【问题标题】:Template function getting argument pack and initializer list模板函数获取参数包和初始化列表
【发布时间】:2016-10-07 10:06:23
【问题描述】:

我有一些像下面这样的模板类

template<typename T>
class A{
  public:
    A(T a0, T a1, T a2):a0_(a0),a1_(a1),a2_(a2){}
  private:
    T a0_,a1_,a2_;
};

template<typename T>
class B{
  public:
    B(T a, std::vector<T> b):a_(a),b_(b){}
  private:
    T a_;
    std::vector<T> b_;
};

template<typename T>
class C{
  public:
    C(T a, T b, std::vector<T> c):a_(a),b_(b),c_(c){}
  private:
    T a_,b_;
    std::vector<T> c_;
};

一般来说,类构造函数有任意数量的参数,最后是可选的std::vector

我希望创建一个 getter 函数来分配上述类的实例。

template< typename C, typename... Args>
C* get(Args... args){
  return new C(args...);
}

当显式创建/定义向量时,getter 函数编译成功。

A<int>* aa = get< A<int> >(1,2,3);

std::vector<int> v({1,2,3});
B<int>* bb = get< B<int> >(1,v);
C<int>* cc = get< C<int> >(1,2,v);

B<int>* bb = get< B<int> >(1,std::vector<int>({1,2,3}));
C<int>* cc = get< C<int> >(1,std::vector<int>({1,2,3}));

为了简单起见,我想使用初始化列表来定义BC 中的向量。这在直接调用构造函数时可以正常工作。

A<int>* aa = new A<int>(1,2,3);
B<int>* bb = new B<int>(1,{1,2,3});
C<int>* cc = new C<int>(1,2,{1,2,3});

getter 函数却给出了编译错误

  B<int>* bb = get< B<int> >(1,{1,2,3});
  C<int>* cc = get< C<int> >(1,2,{1,2,3});

错误:函数的参数太多'C* get(Args ...) [with C = B; Args = {}]'

创建一个像下面这样处理向量的函数特化也是不成功的。

template< typename C, typename T, typename... Args>
C* get(Args... args, std::vector<T> v){
  return new C(args...,v);
}

是否可以创建一个 getter 函数,将参数包和初始化器列表作为最后一个参数并创建对象?

我使用 gcc 5.4 编译。

【问题讨论】:

  • 如果您愿意成为第一,那很容易。否则会很复杂和/或不可能。
  • 感谢@Yakk,但在我的真实来源中,函数是由我定义的。
  • @ztuk 我不明白那个回复。
  • 对不起!我的意思是类的构造函数是由我工作的项目中的其他开发人员定义的

标签: c++ c++11 templates variadic-templates initializer-list


【解决方案1】:

我的建议是:initializer_list 首先。

如果你接受initializer_listget()的第一个参数,你可以写成

template <template<typename> class C, typename T, typename... Args>
C<T>* get(std::initializer_list<T> il, Args ... args){
  return new C<T>(args..., il);
}

称之为

   B<int>* bb = get<B, int>({1,2,3}, 1);
   C<int>* cc = get<C, int>({1,2,3}, 1, 2);

如果你把initializer_list放在最后一个位置,推算Args...这组类型有问题。

显然你需要另一个版本的get() 而不是vector C&lt;T&gt; 类。

OT 建议:您使用的是 C++11,因此您可以(我强烈建议)使用智能指针。

例如,使用unique_ptr,你的get()函数可以变成

template <template<typename> class C, typename T, typename... Args>
std::unique_ptr<C<T>> get(std::initializer_list<T> il, Args ... args)
 { return std::unique_ptr<C<T>>(new C<T>(args..., il)); }

如下使用

std::unique_ptr<B<int>> bb { get<B, int >({1,2,3}, 1) };
std::unique_ptr<C<int>> cc { get<C, int >({1,2,3}, 1, 2) };

--- 编辑---

OP 询问

无论如何,长话短说,我的问题的答案是:不,我 不能有 initializer_list 最后。对吧?

永远不要说“我不能”,但是...

如果你真的,真的想要 initializer_list 在最后的位置...并且如果你可以接受 Args... 参数包含在 std::tuple 中...

template <std::size_t ...>
struct range
 { };

template <std::size_t N, std::size_t ... Next>
struct rangeH 
 { using type = typename rangeH<N-1U, N-1U, Next ... >::type; };

template <std::size_t ... Next >
struct rangeH<0U, Next ... >
 { using type = range<Next ... >; };

template <template<typename> class C, typename T, typename ... Args,
          std::size_t ... I>
std::unique_ptr<C<T>> getH(std::tuple<Args...> const & t,
                           std::initializer_list<T> const & il,
                           range<I...> const)
 { return std::unique_ptr<C<T>>(new C<T>(std::get<I>(t)..., il)); }

template <template<typename> class C, typename T, typename... Args>
std::unique_ptr<C<T>> get(std::tuple<Args...> const & t,
                          std::initializer_list<T> const & il)
 { return getH<C, T>(t, il, typename rangeH<sizeof...(Args)>::type()); }

如下使用

std::unique_ptr<B<int>> bb { get<B, int >(std::make_tuple(1), {1,2,3}) };
std::unique_ptr<C<int>> cc { get<C, int >(std::make_tuple(1, 2), {1,2,3}) };

但是...你真的需要initializer_list 是最后一个位置吗?

我认为最后一个解决方案很糟糕(与前面相比)

【讨论】:

  • 谢谢!我遇到了这个答案stackoverflow.com/a/20059108/2707697 并想到了您的解决方案。无论如何,长话短说,我的问题的答案是:不,我不能最后拥有initializer_list。对吗?
  • @ztik - 嗯...修改了我的答案,试图回答你最后一个问题
  • 我同意你的观点,第二种解决方案似乎并不可取。
【解决方案2】:

它不能从你给它的东西中推断出initializer_list,所以最简单的方法是明确地告诉它是什么。为了使其更简洁,您可以使用以下内容:

template<typename T>
using IL = std::initializer_list<T>;
C<int>* cc2 = get< C<int> >(1, 2, IL<int>{1,2,3});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 2021-11-24
    相关资源
    最近更新 更多