如何扩展对可变参数模板库 类 的调用?
How can I expand call to variadic template base classes?
我有一组非正交策略,它们都实现了一个通用的命名方法,这些策略添加了安全检查。
我希望用户能够组合策略以允许更复杂的验证,而无需手动为每个组合案例创建策略。
我的方法是创建一个新策略 class 来结合其他策略。
下面的简化示例将C作为合并class,这里合并了方法id。预期的结果是,在 C 上调用 id 时,顺序调用每个基的 id class.
#include <iostream>
using namespace std;
struct A
{
void id() { cout << "A ";}
};
struct B
{
void id() { cout << "B ";}
};
template<class A, class... As>
struct C : public A, public As...
{
void id()
{
A::id();
As...::id(); // This line does not work, it is illustrative.
}
};
int main()
{
C<A, B> c;
c.id();
//expected: result A B
}
问题是:是否可以扩展 As... 以某种方式在不使用递归方法的情况下仅使用 ... 运算符来执行此操作?
当然可以。您需要一个允许包扩展的上下文——一个简单的上下文是一个大括号初始化列表,它还具有保证从左到右求值的好处:
using expander = int[];
(void) expander { 0, ((void) As::id(), 0)... };
...
将模式扩展到其左侧;在这种情况下,模式是表达式 ((void) As::id(), 0)
。
表达式中的,
是逗号运算符,它计算第一个操作数,丢弃结果,然后计算第二个操作数,returns结果。
- 存在
As::id()
上的 (void)
是为了防止 operator,
过载,如果您确定 As::id()
的 none 可以省略调用将 return 重载逗号运算符的东西。
逗号运算符右边的0
是因为expander
是一个int
的数组,所以整个表达式(用来初始化一个元素数组)的计算结果必须为 int
。
- 第一个
0
确保我们不会在 As
为空包时尝试创建非法的 0 大小数组。
Demo.
在 C++17 中(如果幸运的话),C::id
的整个主体可以替换为 a binary fold expression: (A::id(), ... , (void) As::id());
Demo。
我有一组非正交策略,它们都实现了一个通用的命名方法,这些策略添加了安全检查。 我希望用户能够组合策略以允许更复杂的验证,而无需手动为每个组合案例创建策略。 我的方法是创建一个新策略 class 来结合其他策略。
下面的简化示例将C作为合并class,这里合并了方法id。预期的结果是,在 C 上调用 id 时,顺序调用每个基的 id class.
#include <iostream>
using namespace std;
struct A
{
void id() { cout << "A ";}
};
struct B
{
void id() { cout << "B ";}
};
template<class A, class... As>
struct C : public A, public As...
{
void id()
{
A::id();
As...::id(); // This line does not work, it is illustrative.
}
};
int main()
{
C<A, B> c;
c.id();
//expected: result A B
}
问题是:是否可以扩展 As... 以某种方式在不使用递归方法的情况下仅使用 ... 运算符来执行此操作?
当然可以。您需要一个允许包扩展的上下文——一个简单的上下文是一个大括号初始化列表,它还具有保证从左到右求值的好处:
using expander = int[];
(void) expander { 0, ((void) As::id(), 0)... };
...
将模式扩展到其左侧;在这种情况下,模式是表达式((void) As::id(), 0)
。表达式中的
,
是逗号运算符,它计算第一个操作数,丢弃结果,然后计算第二个操作数,returns结果。- 存在
As::id()
上的(void)
是为了防止operator,
过载,如果您确定As::id()
的 none 可以省略调用将 return 重载逗号运算符的东西。
逗号运算符右边的 0
是因为expander
是一个int
的数组,所以整个表达式(用来初始化一个元素数组)的计算结果必须为int
。- 第一个
0
确保我们不会在As
为空包时尝试创建非法的 0 大小数组。
Demo.
在 C++17 中(如果幸运的话),C::id
的整个主体可以替换为 a binary fold expression: (A::id(), ... , (void) As::id());
Demo。