2017-08-11 5 views
1

2つの同様の構造AとBがあるとします。AとBの両方にAへのポインタがありますが、AにはAまたはBへの追加ポインタがあります。C++:Baseクラスの派生クラスのみの変数を使用

私は基本と派生クラスAがDerived<0>であり、BはDerived <1>ある

template <bool T> struct Derived; 
struct Base { Derived<0> *p1; }; 
template <> struct Derived<0> : public Base { Base *p2; }; 
template <> struct Derived<1> : public Base {}; 

でこのような何かを考えました。

ここでの問題は、p2でクラスにアクセスすると、コンパイラはそれがどの派生クラスであるのかわからないため、このようなエラーが発生します。

Derived<0> x, y, z; 
x.p2 = &y; 
y.p2 = &z; 
x.p2->p2; // Error 

あなたは魔法の回避策を知っていますか、できればコンパイル時の機能のみを使用していますか?

また、どのタイプのDerivedを使用しているかを知る必要があるため、p2を使用できるかどうかはわかります。

それが助け場合は、p1ポインタで、p2ポインタである、Derived<1>がエンド・ノードで、Derived<0>は通常のノードである二重リンクリスト、として物事を視覚化することができます。

編集:Base-and-Derived-class-type構造を使用する必要はありません。何でも構いません。

+2

'x.p2'が' Base'へのポインタで、 'p2'のメンバーを持たず、' - > p2'が何かに解決できないので、エラーです。 'dynamic_cast >(x.p2)'を実行し、結果が 'nullptr'でないかどうかを確認できます。そうでなければ、キャストされたポインタを通して ' - > p2'にアクセスできます。 – cdhowie

+0

(条件付きで正しくキャストするには、基本クラスが 'dynamic_cast'のために多相でなければならないことに注意してください) – cdhowie

答えて

1

可能な解決策は、最もよく知られている訪問者パターンの背後にある同じ考え方である、二重ディスパッチに基づいています。

それは、最小限の作業例を次に示します。

#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上で実行されています。

+0

うーん、とても素敵なトリックです。ありがとう! – gmardau

関連する問題