1

我有一個類定義如下:鑄造對象到其基地的一個子集

template<typename...> 
class Base; 

template< typename T > 
class Base<T>{ 
    //pure virtual functions dependent on T 
public: 
    virtual ~Base() = default; 
}; 

template< typename... Ts > 
class Base<Ts...> 
: public Base<Ts>... 
{ 
    //empty 
}; 

的問題是:

  • 有沒有辦法投Base< T1, T2, T3 >&Base< T2, T3 >&
  • 有沒有辦法將Base< T1, T2, T3 >&投射到Base< T2, T1, T3 >&

編輯: 讓我改一下這個問題沒有模板。 我已經定義爲一類如下:

class Base_int{ 
public: 
    virtual int f() = 0; 
    virtual ~Base_int() = default; 
}; 
class Base_float{ 
public: 
    virtual float f() = 0; 
    virtual ~Base_float() = default; 
}; 
class Base_double{ 
public: 
    virtual double f() = 0; 
    virtual ~Base_double() = default; 
}; 

class IFD 
: public Base_int 
, public Base_float 
, public Base_double 
{ }; 

class IF 
: public Base_int 
, public Base_float 
{ }; 

class FID 
: public Base_float 
, public Base_int 
, public Base_double 
{ }; 

的問題是:

  • 有沒有辦法投IFD&IF&
  • 有沒有辦法將IFD&轉換爲FID&

編輯2: 爲了進一步澄清: 我impementing,我將使用一個通用的樹容器通用訪問者模式的實現。我使用mixin(CRTP)模式實現訪問類的accept方法以及訪問者的visit方法。這些方法是虛擬的,我需要在OP中發佈的層次結構。 有一個名爲IVisitor<Ts...>的基類實現訪問者的界面,訪問者訪問Ts...。該接口由IVisitor<T>類組成 - 就像在OP中一樣。 實現了IVisitor<Ts...>的具體訪問者的定義如下:

class ConcreteVisitor : public IVisitor<T1, T2, T2, ...>{ 
    //Implementation of the visit methods defined in IVisitor<Ts...> 
    virtual void visit(T1& v) override { /*...*/ } 
    virtual void visit(T2& v) override { /*...*/ } 
    virtual void visit(T3& v) override { /*...*/ } 
} 

它發生,我認爲這將是有用的,如果在ConcreteVisitor可在IVisitor<Us...>參觀的東西,其中Us...是一個子集,或Ts...置換。爲了做到這一點,我需要將它投射到這個基地 - 因此是一個問題。

+1

'基地'不從'基地< T2, T3 >繼承'既不從'基地' 。您只應該投射到對象正在執行的類中以避免未定義的行爲... –

+1

您是否正在尋找Mixin模式? – lorro

+0

我的狀態仍然有效...'IFD'不會從'IF'繼承,因此您不應該將'IFD'的引用強制轉換爲'IF'。這同樣適用於'FID'。你想要達到什麼目的?因爲也許還有其他的方法可以做到這一點...... –

回答

1

檢查問題多一些後,我意識到我需要一個適應一般遊客到我的接口的包裝。這是我與去溶液 - 參見IVisitable::adaptVisitor靜態方法:

#include <iostream> 
#include <typeinfo> 
#include <vector> 

//Visitable base class 
template<typename> 
class Visitable; 

    //Visitable class interface 
template<typename...> 
class IVisitor; 

    //Assures that the visitor type derives from IVisitor 
template< typename IVisitor_type > 
class IVisitable 
: public IVisitable<typename IVisitor_type::derives_from_IVisitor> 
{ }; 

    //Implements the Visitor adapter 
template< typename Derived, typename Root, typename... Ts > 
class VisitorWrapper; 

    //IVisitable base class 
template< typename... Ts > 
class IVisitable< IVisitor<Ts...> >{ 
public: 
    //Visitor interface type 
    using IVisitor = IVisitor<Ts...>; 

    //Visitor adapter type 
    template< typename F > 
    class VisitorAdapter; 

    //Helper function 
    template< typename F > 
    static VisitorAdapter<F&&> adaptVisitor(F&& f) 
    { return { std::forward<F>(f) }; } 

    //Accept visitor pure virtual methods 
    virtual void accept(IVisitor& )  = 0; 
    virtual void accept(IVisitor& ) const = 0; 
    virtual void accept(IVisitor&&)  = 0; 
    virtual void accept(IVisitor&&) const = 0; 

protected: 
    virtual ~IVisitable() = default; 
}; 

    //Implements the visitor adapter of F class 
template< typename... Ts > 
template< typename F > 
class IVisitable<IVisitor<Ts...>>::VisitorAdapter 
    : public VisitorWrapper< VisitorAdapter<F>, ::IVisitor<Ts...>, Ts... > 
     //Derives from VisitorWrapper that implements all of the virtual methods 
{ 
public: 
    template< typename U > 
    void visit(U&& u){ f(std::forward<U>(u)); } 

    VisitorAdapter(F f_) : f(f_) { } 

    F f; 
}; 

    //Basic IVisitor of T 
template< typename T > 
class IVisitor<T>{ 
public: 
    using derives_from_IVisitor = IVisitor; 

    virtual void visit(  T&) = 0; 
    virtual void visit(const T&) = 0; 

    virtual ~IVisitor()    = default; 
}; 

    //IVisitor of Ts derives from Visitor<T> 
template< typename T, typename... Ts > 
struct IVisitor<T, Ts...> 
: IVisitor<T>, IVisitor<Ts...> 
{ 
    using derives_from_IVisitor = IVisitor; 
}; 

    //Visitable base class. Final to prevent errors 
template< typename Derived > 
struct Visitable final 
{ 
    //Extends class wraps the Base class inheritance 
    template< typename Base > 
    class extends : public Base 
    { 
    public: 
     //Propagate the IVisitor interface. 
    using IVisitor = typename Base::IVisitor; 

     //Prevents incomprehensible errors when visitor doesn't 
     //define Derived as its visited class 
    static_assert(
     std::is_base_of<::IVisitor<Derived>, IVisitor>::value 
    , "Base class visitor interface does not support visitation of this type" 
    ); 

    //Implement accept method via CRTP 
    virtual void accept(IVisitor& v) override{ 
     static_cast< ::IVisitor<Derived>& >(v).visit( // Disambiguation 
     static_cast<Derived&>(*this)     // CRTP 
    ); 
    } 
    virtual void accept(IVisitor& v) const override { 
     static_cast< ::IVisitor<Derived>& >(v).visit( // Disambiguation 
     static_cast<const Derived&>(*this)    // CRTP 
    ); 
    } 
    virtual void accept(IVisitor&& v) override{ 
     static_cast< ::IVisitor<Derived>&& >(v).visit( // Disambiguation 
     static_cast<Derived&>(*this)     // CRTP 
    ); 
    } 

    virtual void accept(IVisitor&& v) const override{ 
     static_cast< ::IVisitor<Derived>&& >(v).visit( // Disambiguation 
     static_cast<const Derived&>(*this)    // CRTP 
    ); 
    } 
    protected: 
    virtual ~extends() = default; 
    }; 

    ~Visitable() = delete; 
}; 

template<typename> struct print_type; 

//Uses CRTP to implement visit method of IVisitor 
//Consumes the list of Ts... so that the inheritance hierarchy is linear 
template< 
    typename Derived // CRTP 
, typename... Rs // Base class (IVisitor<Rs...>) 
, typename T  // Currently implemented type 
, typename... Ts // The rest of types 
> class VisitorWrapper< Derived, IVisitor<Rs...>, T, Ts... > 
: public VisitorWrapper< Derived, IVisitor<Rs...>, Ts... > //Consume T 
{ 
    //Cast to Derived and call visit method 
    virtual void visit(  T& v){ static_cast<Derived*>(this)->visit(v); } 
    virtual void visit(const T& v){ static_cast<Derived*>(this)->visit(v); } 
}; 

//Uses CRTP to implement visit method of IVisitor 
template< typename Derived, typename... Rs, typename T > 
class VisitorWrapper< Derived, IVisitor<Rs...>, T > 
: public IVisitor<Rs...> //IVisitor<Ts...> 
{ 
    virtual void visit(  T& v){ static_cast<Derived*>(this)->visit(v); } 
    virtual void visit(const T& v){ static_cast<Derived*>(this)->visit(v); } 
}; 

///////////////////////////////////////////////////// 

class ABCVisitor 
: public IVisitor< class A, class B, class C > 
{ }; 

class ABC : public IVisitable<ABCVisitor> 
{}; 

class A : public Visitable<A>::extends<ABC> {}; 
class B : public Visitable<B>::extends<ABC> {}; 
class C : public Visitable<C>::extends<B> {}; 

int main() 
{ 
    auto p = [](const auto& v){ std::cout << typeid(v).name() << std::endl; }; 
    auto printer = ABC::adaptVisitor(p); 
    A a; B b; C c; 
    std::vector< ABC* > vs{ &a, &b, &c }; 
    for(const auto& v : vs) 
    v->accept(printer); 
    return 0; 
} 
0

我不確定這是你在找什麼,但在這裏。 我會使基類模板的accept方法模板化,以便只要訪問者有正確的概念,他們就可以接受任何訪問者。特別是:

#include <iostream> 

template <class Derived> 
struct Base { 

    // templated visitor so that it can take any argument as long as it has the right concept 
    template <class Visitor> 
    void accept(Visitor& visitor) { 
     visitor.visit(static_cast<Derived&>(*this)); 
    } 
}; 

struct T1 
: Base<T1> {}; 

struct T2 
: Base<T2> {}; 

struct T3 
: Base<T3> {}; 

struct Visitor1 { 

    void visit(T1& t1) { 
     std::cout << "Visiting T1 from Visitor1" << std::endl; 
    } 

    void visit(T2& t2) { 
     std::cout << "Visiting T2 from Visitor1" << std::endl; 
    } 
}; 


struct Visitor2 { 

    void visit(T1& t1) { 
     std::cout << "Visiting T1 from Visitor2" << std::endl; 
    } 

    void visit(T2& t2) { 
     std::cout << "Visiting T2 from Visitor2" << std::endl; 
    } 

    void visit(T3& t3) { 
     std::cout << "Visiting T3 from Visitor2" << std::endl; 
    } 
}; 




int main(int argc, const char * argv[]) { 
    Visitor1 visitor1; 
    Visitor2 visitor2; 
    T1 t1; 
    T2 t2; 
    T3 t3; 
    t1.accept(visitor1); 
    t1.accept(visitor2); 
    t2.accept(visitor1); 
    t2.accept(visitor2); 
    t3.accept(visitor2); 
// t3.accept(visitor1); // triggers a compilation error as visitor1 cannot handle T3 types 
} 

這樣你就不再需要做任何你的訪客類的演員。

0

我不認爲你需要使用排列參數強制轉換爲訪問者來完成你想要的任務,唯一需要的是額外的抽象級別 - 可變模板包裝器給你的訪問者。找到下面的代碼:

struct VisitorParent { 
    virtual ~VisitorParent() = default; 
}; 

template <class T> 
struct VisitorImpl: virtual VisitorParent { 
    virtual void visit(T &t) { 
     //... 
    } 
}; 

template <class... Ts> 
struct Visitor: virtual VisitorImpl<Ts>... { }; 

template <class T> 
struct VisitorWrapperImpl { 
    VisitorParent *vp; 
    VisitorWrapperImpl(VisitorParent *vp): vp(vp) {} 
    void visit(T &t) { 
     VisitorImpl<T> *cvi = dynamic_cast<VisitorImpl<T> *>(vp); 
     if (cvi) { 
     cvi->visit(t); 
     } 
    } 
}; 

template <class... Ts> 
struct VisitorWrapper: VisitorWrapperImpl<Ts>... { 
    VisitorWrapper(VisitorParent *vp): VisitorWrapperImpl<Ts>(vp)... { } 
    template <class T> 
    void visit(T &t) { 
     VisitorWrapperImpl<T>::visit(t); 
    } 
}; 

int main() { 
    Visitor<int, char, float> v; 
    VisitorWrapper<char,float> vw(&v); 
    char c; 
    vw.visit(c); 
} 
0

另一個想法是讓接受方法採取的訪問者的基類之一。通過這種方式,您可以將任何訪問者傳遞給接受方法,因爲所有訪問者都可以被轉換爲單個訪問者類。我相信這會爲你工作:

#include <iostream> 

// one of the base classes of your concrete visitors 
template <class T> 
struct VisitorUnit { 

    virtual void visit(T& t) = 0; 
}; 

// the visitor interface which will be implemented by concrete visitors 
template <class... T> 
struct Visitor 
: VisitorUnit<T>... { 

}; 

// the base class of your leaf classes 
template <class Derived> 
struct Base { 

    void accept(VisitorUnit<Derived>& visitor) { 
     visitor.visit(static_cast<Derived&>(*this)); 
    } 
}; 

struct T1: Base<T1>{}; 
struct T2: Base<T2>{}; 
struct T3: Base<T3>{}; 

struct Visitor1 
: Visitor<T1, T2, T3> { 

    void visit(T1& t) override { 
     std::cout << "T1 from Visitor1" << std::endl; 
    } 

    void visit(T2& t) override { 
     std::cout << "T2 from Visitor1" << std::endl; 
    } 

    void visit(T3& t) override { 
     std::cout << "T3 from Visitor1" << std::endl; 
    } 
}; 

struct Visitor2 
: Visitor<T3, T2> { 


    void visit(T2& t) override { 
     std::cout << "T2 from Visitor2" << std::endl; 
    } 

    void visit(T3& t) override { 
     std::cout << "T3 from Visitor2" << std::endl; 
    } 
}; 



int main(int argc, const char * argv[]) { 
    T1 t1; 
    T2 t2; 
    T3 t3; 
    Visitor1 visitor1; 
    Visitor2 visitor2; 

    visitor1.visit(t1); 
    visitor1.visit(t2); 
    visitor1.visit(t3); 

    visitor2.visit(t2); 
    visitor2.visit(t3); 


} 
+0

不幸的是,這不會做T1,T2和T3需要從單個基類派生。我需要他們,所以我可以使用類型擦除。 – tsuki

+0

@tsuki:您提到您正在使用CRTP作爲accept方法,這是我在上面使用的方法。你是如何實現它的? – linuxfever

+0

我發佈了答案。 – tsuki