4

我的程序的目的是创建一个数据列表,在我的类层次结构中使用静态多态性时,我可以使用一组静态访问者访问该列表。

我通过 CRTP 创建了一个利用静态多态性的类层次结构:

class VirtualBaseData {
public:    
    //someVirtualFunction
}

template<typename Derived>
class BaseData<Derived> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         static_cast<Derived*>(this)->accept(v);
    }
}

class DerivedBaseData1: BaseData<DerivedBaseData> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         //Specific implementation
    }    
}
class DerivedBaseData2: BaseData<DerivedBaseData> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         //Specific implementation
    }    
}

我想将 DerivedBaseData 存储在一个包含中,以便以后迭代和访问。

int main(){
    std::vector<VirtualBaseData*> dataSet;
    dataSet.push_back(new DerivedBaseData1);
    dataSet.push_back(new DerivedBaseData2);
    for(auto it = fifth.begin(); it != fifth.end(); ++it){
        it->accept(); //Error: VirtualBaseData does not have a member function accept
    }
}

我正在寻找一种将我的静态访问者与我的静态多态层次结构相结合的方法。我的静态多态性中需要一个 VirtualBaseData 类,它不是模板类,以便在容器中使用这些类。但是,由于我不能让 VirtualBaseData 类成为模板类,因此我无法像在 CRTPattern 中那样为派生类创建适当的 static_cast。

我的问题是:有没有人有一个好的策略可以保留我的静态多态设置以及静态访问者模式?

供参考:我已经按照http://hillside.net/plop/2006/Papers/Library/portableProgrammingPL.pdf第 21-23 页中的描述实现了我的静态访问者

4

3 回答 3

1

如果你不知道你的对象在编译时会有多少/什么类型,那么它是动态多态的一个用例(至少,我不知道如何只使用静态多态来做到这一点)。

但是...如果您在编译时知道对象的确切数量和类型,那么现在我们正在谈论!这是一个最小的编译示例(ideone 上的代码):

#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;


template<typename Derived>
class BaseData {
public:
    template<typename Visitor>
    void accept(Visitor &v){
         static_cast<Derived*>(this)->accept(v);
    }
};

class DerivedBaseData1: BaseData<DerivedBaseData1> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
        std::cout << "DerivedBaseData1: accepting visitor " << v << std::endl;
    }    
};
class DerivedBaseData2: BaseData<DerivedBaseData2> {
public:
    template<typename Visitor>
    void accept(Visitor &v){
        std::cout << "DerivedBaseData2: accepting visitor " << v << std::endl;
    }    
};

namespace impl {

    template <size_t N> 
    struct num2type {};

    template <size_t Idx, typename T, typename Visitor>
    void accept_impl(Visitor &v, T &&collection, num2type<Idx>) {
        // run accept on current object
        auto &object = std::get<Idx>(collection);
        object.accept(v);
        // move iteration forward
        accept_impl(v, std::forward<T>(collection), num2type<Idx - 1>{});
    }

    template <typename T, typename Visitor>
    void accept_impl(Visitor &v, T &&collection, num2type<0>) {
        // run accept on current object
        auto &object = std::get<0>(collection);
        object.accept(v);
    }
}

template<typename ...Ts, typename Visitor>
void accept(Visitor &v, std::tuple<Ts...> &&collection) {
    using T = decltype(collection);
    impl::accept_impl(v, std::forward<T>(collection), impl::num2type<std::tuple_size<std::decay_t<T>>::value - 1>{});
}


int main() {
    using visitor_type = int;
    visitor_type visitor = 42;

    DerivedBaseData1 a1, a3;
    DerivedBaseData2 a2;
    accept(visitor, std::tie(a1, a2, a3));

    return 0;
}

使用静态多态性,您可以迭代静态集合(此处为 a std::tuple)并在每个集合上使用所需的参数调用所需的方法。

于 2016-06-05T18:50:35.490 回答
0

错误是正确的,因为您创建了 VirtualBaseData 指针向量。VirtualBaseData 类不包含 accept() 函数。

你的答案是: C++ 类成员函数模板可以是虚拟的吗?

还阅读了有关多态性的信息: http ://www.cplusplus.com/doc/tutorial/polymorphism/

于 2016-06-05T16:09:06.347 回答
0

正如您所说,没有简单的解决方案,但您可能希望使用运行时多态性而不是静态的。为了归档运行时多态性,您需要对基类执行类型擦除并分派到适当的非模板函数。例如,这可以boost::any从 boost 库中存档。约束boost::any是所有存储为的对象都boost::any必须是可复制的。如果boost::any不适合您,请阅读有关类型擦除的更多信息。

class VirtualBaseData {
public:    
    template <typename T>
    void accept(T& visitor) {
        acceptImpl(boost::any(visitor));
    }
protected:
    virtual void acceptImpl(boost::any const & value ) = 0;
}
于 2016-06-05T16:26:14.250 回答