可变模板构造函数来构建父模板
Variadic Template Constructor to build Parent
我尝试从一堆我知道接口的类继承,但是它们可能有非常不同的构造函数。为此,我决定在派生类构造函数中使用可变模板,以便它可以获得任意参数,这些参数最终将提供给父类。
我的代码如下:#include <iostream>
struct A {
A(int) { std::cout << "This is intn"; }
A(unsigned) { std::cout << "This is unsignedn"; }
};
struct B {
B(char) { std::cout << "This is charn"; }
};
template <typename T>
struct C : public T {
template <typename... Args>
C(double, Args&&... params) : T(std::forward<Args>(params)...) { std::cout << "This is doublen"; }
// But what about this?
// C(Args&&... params, double) : T(std::forward<Args>(params)...) { std::cout << "This is doublen"; }
};
int main() {
C<A> p(1.0, 1);
C<A> r(1.0, 1u);
C<B> q(1.0, 'c');
// Which would work as following
// C<A> p(1, 1.0);
// C<A> r(1u, 1.0);
// C<B> q('c', 1.0);
return 0;
}
我的问题是:
- 这个代码正确吗?这是我第一次尝试在构造器中使用可变模板,所以如果我错过了什么,我很想听听你的意见。
- 我更愿意在最后留下子类
C
的参数,但是据我所知,这是不可能的,因为在构造函数中不允许指定模板参数,在这种情况下,可变参数将吞噬所有参数,不给实际的孩子留下任何参数。有什么办法能做到这一点吗?
14.8.2.1从函数调用中推导模板实参
1[…对于没有出现在参数声明列表末尾的函数参数包,参数包的类型是一个非推导的上下文。
5[…[注意:如果模板参数没有在函数模板的任何函数形参中使用,或者仅在非推导的上下文中使用,则其对应模板参数不能从函数调用中推导出来,必须显式指定模板参数。- 结束说明]
14.8.2.5从类型
推导模板参数如果模板形参仅在未推导的上下文中使用且未显式指定,则模板实参推导失败。
因此,正如您所看到的,Args...
应该被显式指定,但由于这对于构造函数是不可能的,因此这将不起作用。
的作用是将用于基构造函数的所有参数打包到一个元组中(实际示例),后面跟着派生类的剩余参数:
template <typename T>
class C : public T
{
template<typename... A, size_t... I>
C(std::tuple<A...>&& a, sizes<I...>, double x) :
T(std::get<I>(std::move(a))...) { std::cout << "This is doublen"; }
public:
template<typename... A>
C(std::tuple<A...>&& a, double x) :
C(std::move(a), idx<sizeof...(A)>{}, x) { }
};
用作
int main() {
C<A> p(std::forward_as_tuple(1), 1.0);
C<A> r(std::forward_as_tuple(1u, 2.), 1.0);
C<B> q(std::forward_as_tuple('c', 0), 1.0);
}
我使你的例子更丰富:
struct A {
A(int) { std::cout << "This is intn"; }
A(unsigned, double) { std::cout << "This is unsigned, doublen"; }
};
struct B {
B(char, int) { std::cout << "This is char, intn"; }
};
和剩余的样板
template<size_t... I> struct sizes { using type = sizes<I...>; };
template<size_t N, size_t K = 0, size_t... I>
struct idx_t : idx_t<N, K+1, I..., K> {};
template<size_t N, size_t... I>
struct idx_t<N, N, I...> : sizes<I...> {};
template<size_t N>
using idx = typename idx_t<N>::type;
只在std::integer_sequence可用之前存在。
如果你发现std::forward_as_tuple
的名字太长了,那么定义你自己的名字并不难,例如pack
:
template<typename... A>
constexpr std::tuple<A&&...>
pack(A&&... a) { return std::tuple<A&&...>{std::forward<A>(a)...}; }
尽管如此,语法
C<B> q(pack('c', 0), 1.0);
确实增加了一点开销,但我发现最终用户很自然地知道发生了什么。如果向派生类构造函数中添加更多的参数,那么扁平化到C<B> q('c', 0, 1.0);
不仅几乎不可能实现,而且还会使用户产生歧义和混淆。真正酷的是像
C<B> q('c', 0; 1.0);
(也可以在函数中分隔输入/输出参数),但我没有在任何语言中见过这个,只在教科书中见过。
相关文章:
- "error: no matching function for call to"构造函数错误
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 选择要调用的构造函数
- 如何委托派生类使用其父构造函数?
- pair的两个构造函数几乎相同,为什么不生成构建错误?
- 2个模板构造函数的组合构建与变异模板.如何
- 为链接列表构建迭代器类(错误:无匹配的构造函数以初始化)
- 是否可以使用多个参数构建类的构造函数
- 在C 构建器中超载Mainform构造函数
- 找不到构造函数 - 如何将 CPP 文件添加到 Qt 构建过程
- 通过转发构造函数参数来构建基于可变参数模板的 mixin
- 我如何构建具有构造函数参数的对象的向量
- 使用子字符串构造函数构建字符串 - 调试 - 当自动跳过代码时
- 2-3树以及如何构建构造函数
- clang与gcc运行时的区别:用clang构建的c++类模板在没有复制构造函数的情况下崩溃,用复制构造函数构建的gcc
- 可变模板构造函数来构建父模板
- 如何构建一个合适的构造函数和析构函数