模板函数获取参数包和初始化列表
Template function getting argument pack and initializer list
我有一些模板化的 类 如下所示
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...);
}
当向量显式 created/defined 时,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}));
为了简单起见,我想使用初始化列表来定义B
和C
中的向量。这在直接调用构造函数时工作正常。
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});
error: too many arguments to function ‘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编译。
它无法从您提供的内容中推断出 initializer_list
,因此最简单的方法是明确说明它是什么。为了使它更简洁,你可以使用这样的东西:
template<typename T>
using IL = std::initializer_list<T>;
C<int>* cc2 = get< C<int> >(1, 2, IL<int>{1,2,3});
我的建议是:initializer_list
先
如果你接受initializer_list
是get()
的第一个参数,你可以把它写成
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<T>
类.
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 问
In any case, long story short, the answer to my question is: No, I
cannot have the initializer_list last. Right?
永远不要说 "I cannot" 但是...
如果你真的,真的想要最后一个位置的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
是最后一个位置吗?
我认为最后一个解决方案很糟糕(与前面的解决方案相比)
我有一些模板化的 类 如下所示
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...);
}
当向量显式 created/defined 时,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}));
为了简单起见,我想使用初始化列表来定义B
和C
中的向量。这在直接调用构造函数时工作正常。
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});
error: too many arguments to function ‘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编译。
它无法从您提供的内容中推断出 initializer_list
,因此最简单的方法是明确说明它是什么。为了使它更简洁,你可以使用这样的东西:
template<typename T>
using IL = std::initializer_list<T>;
C<int>* cc2 = get< C<int> >(1, 2, IL<int>{1,2,3});
我的建议是:initializer_list
先
如果你接受initializer_list
是get()
的第一个参数,你可以把它写成
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<T>
类.
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 问
In any case, long story short, the answer to my question is: No, I cannot have the initializer_list last. Right?
永远不要说 "I cannot" 但是...
如果你真的,真的想要最后一个位置的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
是最后一个位置吗?
我认为最后一个解决方案很糟糕(与前面的解决方案相比)