想象一下,我有两个相似的结构A和B。A和B都具有指向A的指针,但是A具有指向A或B的附加指针。
我想到了这样的基类和派生类
template <bool T> struct Derived;
struct Base { Derived<0> *p1; };
template <> struct Derived<0> : public Base { Base *p2; };
template <> struct Derived<1> : public Base {};
其中A是Derived<0>
,B是Derived <1>
。
这里的问题是,当通过访问一个类时p2
,编译器不知道它是哪个派生类,而这样的操作会产生错误。
Derived<0> x, y, z;
x.p2 = &y;
y.p2 = &z;
x.p2->p2; // Error
你们是否知道任何神奇的解决方法,最好仅使用编译时功能?
我还需要知道我使用的是哪种类型的“派生”,以便知道我是否可以使用p2。
如果有帮助,你可以想像的事情作为一个双链表,这里Derived<0>
是一个正常的节点,Derived<1>
是终端节点,p1
是上一个指针,p2
是下一个指针。
编辑:它不需要使用基类和派生类类型的结构,它可以是任何东西。
一种可能的解决方案是基于双重调度,即最知名的访客模式背后的想法。
它遵循一个最小的有效示例:
#include<iostream>
template<int>
struct Derived;
struct Visitor {
template<int N>
void visit(Derived<N> &);
};
struct Base {
Derived<0> *p1;
virtual void accept(Visitor &) = 0;
};
template<>
struct Derived<0>: public Base {
void accept(Visitor &) override;
Base *p2;
};
template<>
struct Derived<1>: public Base {
void accept(Visitor &) override;
};
template<>
void Visitor::visit(Derived<0> &d) {
std::cout << "Derived<0>" << std::endl;
d.p2->accept(*this);
}
template<>
void Visitor::visit(Derived<1> &) {
std::cout << "Derived<1>" << std::endl;
}
void Derived<0>::accept(Visitor &v) {
v.visit(*this);
}
void Derived<1>::accept(Visitor &v) {
v.visit(*this);
}
int main() {
Visitor v;
Derived<0> x, y;
Derived<1> z;
x.p2 = &y;
y.p2 = &z;
x.p2->accept(v);
}
看到它并在wandbox上运行。
如果可以使用C ++ 17,则可以std::variant
轻松得多:
#include<iostream>
#include<variant>
template<int>
struct Derived;
struct Base {
Derived<0> *p1;
};
template<>
struct Derived<0>: public Base {
std::variant<Derived<0> *, Derived<1> *> p2;
};
template<>
struct Derived<1>: public Base {};
struct Visitor {
void operator()(Derived<0> *d) {
std::cout << "Derived<0>" <<std::endl;
std::visit(*this, d->p2);
}
void operator()(Derived<1> *) {
std::cout << "Derived<1>" <<std::endl;
}
};
int main() {
Visitor v;
Derived<0> x, y;
Derived<1> z;
x.p2 = &y;
y.p2 = &z;
std::visit(v, x.p2);
}
看到它并在wandbox上运行。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句