使用可变参数模板的递归继承
Recursive inheritance with variadic templates
请考虑以下代码:
#include <iostream>
struct ActionOption {
virtual void foo(int) const = 0;
};
template <int> struct ActionType;
template <> struct ActionType<0> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<0>::foo(int) called.n";}
};
template <> struct ActionType<1> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<1>::foo(int) called.n";}
};
template <> struct ActionType<2> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<2>::foo(int) called.n";}
};
template <> struct ActionType<3> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<3>::foo(int) called.n";}
};
template <> struct ActionType<4> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<4>::foo(int) called.n";}
};
template <int...> struct PossibleActions;
template <> struct PossibleActions<> { void operator()(int) const {} };
template <int First, int... Rest>
struct PossibleActions<First, Rest...> : ActionType<First>, PossibleActions<Rest...> {
void operator()(int a) const {
ActionType<First>::foo(a);
PossibleActions<Rest...>::operator()(a);
}
};
// Anything that can call ActionType<2>::foo(int) can also call ActionType<3>::foo(int).
struct Object : PossibleActions<1, 2,3, 4> {
void foo(int a) {PossibleActions<1,2,3,4>()(a);}
};
struct Blob : PossibleActions<0, 2,3, 4> {
void foo(int a) {PossibleActions<0,2,3,4>()(a);}
};
int main() {
Object object;
object.foo(12); // ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Blob blob;
blob.foo(12); // ActionType<0>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
}
它运行,除了这里是问题:任何可以调用ActionType<2>::foo(int)
的东西也可以调用ActionType<3>::foo(int)
。 因此,每次我定义一个新类时,如果我使用 2 或 3,我必须在 PossibleActions<I...>
中使用两者。 当然,这对维护来说是有问题的(假设我决定将来使用 2 也必须使用 3、7 和 20)。 以下解决方案:
using TwoAndThree = PossibleActions<2,3>;
struct Object : PossibleActions<1,4>, TwoAndThree {
void foo(int a) {PossibleActions<1,4>()(a); TwoAndThree()(a);}
};
struct Blob : PossibleActions<0,4>, TwoAndThree {
void foo(int a) {PossibleActions<0,4>()(a); TwoAndThree()(a);}
};
是不可接受的,因为我需要按数字顺序调用ActionType<N>::foo(int)
。 拆分PossibleActions<1,4>()(a);
也是一个非常糟糕的解决方案,因为它遇到了相同的维护问题(我认为使维护变得更糟)。
template <> struct ActionType<2> : ActionOption { virtual void foo(int) const override {std::cout << "ActionType<2>::foo(int) called.n";} };
template <> struct ActionType<3> : ActionType<2> { virtual void foo(int) const override {std::cout << "ActionType<3>::foo(int) called.n";} };
由于歧义而无法编译(使用虚拟继承没有帮助),我想不出其他任何东西。 这个问题有解决方案吗?
也许用template <typename... Args> struct PossibleActions;
重新定义可能的操作? 但是递归就丢失了。
还是吗?
相关问题:有没有办法使用 Args 执行递归......其中某些类型是 int 但有些不是(以及那些不使用递归的类型与定义这些类型的 int)? 例如
PossibleActions<1, TwoAndThree, 4, EightAndTen, 20>()(a);
根据需要遍历 1,2,3,4,8,10,20,因为TwoAndThree = PossibleActions<2,3>
和EightAndTen = PossibleActions<8,10>
??? 如果可能的话,这将解决问题。
功劳归于Piotr。S这个解决方案(我希望我能给他积分,但他出于某种原因喜欢隐藏他的惊人)。 虽然他的第二个解决方案也很好,但我更喜欢他的第一个解决方案提供的语法。 他的排序结构必须推广为
template <typename, typename...> struct Sort;
template <typename T, typename A, typename B>
struct Sort<T,A,B> {
using type = typename Merge<T,A,B>::type;
};
template <typename T, typename First, typename Second, typename... Rest>
struct Sort<T, First, Second, Rest...> {
using type = typename Sort<T, typename Sort<T, First, Second>::type, Rest...>::type;
};
所以我为他做了。 这允许语法
struct Widget : Sort<PossibleActions<0,5>, OneAndFour, TwoAndThree>
我更喜欢。 我也在图片中添加了模板模板:
#include <iostream>
namespace Detail {
template <typename T, typename, typename, T...> struct Merge;
template <typename T, template <T...> class S, T... Ks>
struct Merge<T, S<>, S<>, Ks...> {
using type = S<Ks...>;
};
template <typename T, template <T...> class S, T... Is, T... Ks>
struct Merge<T, S<Is...>, S<>, Ks...> {
using type = S<Ks..., Is...>;
};
template <typename T, template <T...> class S, T... Js, T... Ks>
struct Merge<T, S<>, S<Js...>, Ks...> {
using type = S<Ks..., Js...>;
};
template <typename T, bool, typename, typename, T...> struct Strip;
template <typename T, template <T...> class S, T I, T... Is, T J, T... Js, T... Ks>
struct Strip<T, true, S<I, Is...>, S<J, Js...>, Ks...> {
using type = Merge<T, S<I, Is...>, S<Js...>, Ks..., J>;
};
template <typename T, template <T...> class S, T I, T... Is, T J, T... Js, T... Ks>
struct Strip<T, false, S<I, Is...>, S<J, Js...>, Ks...> {
using type = Merge<T, S<Is...>, S<J, Js...>, Ks..., I>;
};
template <typename T, template <T...> class S, T I, T... Is, T J, T... Js, T... Ks>
struct Merge<T, S<I, Is...>, S<J, Js...>, Ks...> : Strip<T, (I > J), S<I, Is...>, S<J, Js...>, Ks...>::type {};
template <typename, typename...> struct Sort;
template <typename T, typename A, typename B>
struct Sort<T,A,B> {
using type = typename Merge<T,A,B>::type;
};
// Piotr S.'s Sort generalized to accept any number of template arguments.
template <typename T, typename First, typename Second, typename... Rest>
struct Sort<T, First, Second, Rest...> {
using type = typename Sort<T, typename Sort<T, First, Second>::type, Rest...>::type;
};
}
template <typename... P>
using Sort = typename Detail::Sort<int, P...>::type;
struct ActionOption {
virtual void foo(int) const = 0;
};
template <int> struct ActionType;
template <> struct ActionType<0> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<0>::foo(int) called.n";}
};
template <> struct ActionType<1> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<1>::foo(int) called.n";}
};
template <> struct ActionType<2> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<2>::foo(int) called.n";}
};
template <> struct ActionType<3> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<3>::foo(int) called.n";}
};
template <> struct ActionType<4> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<4>::foo(int) called.n";}
};
template <> struct ActionType<5> : ActionOption {
virtual void foo(int) const override {std::cout << "ActionType<5>::foo(int) called.n";}
};
template <int...> struct PossibleActions;
template <> struct PossibleActions<> { void operator()(int) const {} };
template <int First, int... Rest>
struct PossibleActions<First, Rest...> : ActionType<First>, PossibleActions<Rest...> {
void operator()(int a) const {
ActionType<First>::foo(a);
PossibleActions<Rest...>::operator()(a);
}
};
using OneAndFour = PossibleActions<1,4>;
using TwoAndThree = PossibleActions<2,3>;
struct Thing : PossibleActions<0,1,2,3,4> {
void foo(int a) {PossibleActions<0,1,2,3,4>::operator()(a);}
};
struct Object : Sort<PossibleActions<1,4>, TwoAndThree> {
void foo(int a) {Sort<PossibleActions<1,4>, TwoAndThree>()(a);}
};
struct Blob : Sort<PossibleActions<0,4>, TwoAndThree> {
void foo(int a) {Sort<PossibleActions<0,4>, TwoAndThree>()(a);}
};
struct Widget : Sort<PossibleActions<0,5>, OneAndFour, TwoAndThree> {
void foo(int a) {Sort<PossibleActions<0,5>, OneAndFour, TwoAndThree>()(a);}
};
int main() {
Thing thing;
thing.foo(12); // ActionType<0>::foo(int) ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Object object;
object.foo(12); // ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Blob blob;
blob.foo(12); // ActionType<0>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called
std::cout << std::endl;
Widget widget;
widget.foo(12); // ActionType<0>::foo(int) called ActionType<1>::foo(int) called ActionType<2>::foo(int) called ActionType<3>::foo(int) called ActionType<4>::foo(int) called ActionType<5>::foo(int) called
}
但是请注意,如果原始包本身未排序,则解决方案实际上会失败。 这可能需要在执行上述操作之前先在原始包装上使用辅助分拣器结构。
- 通过递归进行因子分解
- 递归函数计算序列中的平方和(并输出过程)
- 使用递归的数组的最小值.这是怎么回事
- 递归列出所有目录中的C++与Python与Ruby的性能
- 递归计数给定目录的文件和所有目录
- 如何在BST的这个简单递归实现中消除警告
- C++:正在检查LinkedList中的回文-递归方法-错误
- 递归模板化函数不能分配给具有常量限定类型"const tt &"的变量"state"
- 递归无序映射
- TSP递归解的迭代形式
- 如何在Elixir中调用递归函数并行
- 带有递归继承和使用声明的Variadic模板
- 用类型的递归继承获得Variadic模板的阴影成员
- 通过类型C++ 的继承树递归导致此指针问题
- 具有可变模板的递归继承和继承参数问题
- 使用可变参数模板的递归继承
- 为什么对std::tuple实现使用递归继承不好
- 从递归模板类继承
- 从递归定义的类继承
- 具有合成和继承属性的深度递归qi语法(解析器)