我的程序的目的是创建一个数据列表,当在类层次结构中使用静态多态性时,我可以使用一组静态访问者访问该列表。
我通过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。
我的问题是:有人有一个好的策略可以保留我的静态多态性设置和静态访问者模式吗?
供参考:我已经实现了我的静态访问者,如中的第21-23页所述http://hillside.net/plop/2006/Papers/Library/portableProgrammingPL.pdf
如果你不知道在编译时你的对象有多少/什么类型,那么这就是动态多态性的用例(至少,我不知道如何只使用静态多态性)。
然而。。。如果您在编译时知道对象的确切数量和类型,现在我们就开始讨论了!下面是一个最小编译示例(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;
}
使用静态多态性,您可以迭代一个静态集合(这里是std::tuple
),并在每个集合上使用所需的参数调用所需的方法。
错误是正确的,因为您创建了VirtualBaseData指针的向量。类VirtualBaseData不包含accept()函数。
你的答案是:C++类成员函数模板可以是虚拟的吗?
还阅读了多态性:http://www.cplusplus.com/doc/tutorial/polymorphism/
正如您所说,没有简单的解决方案,但您可能希望使用运行时多态性而不是静态。为了归档运行时多态性,您需要对基类执行类型擦除,并将其分派给适当的非temaple函数。这可以存档,例如使用boost库中的boost::any
。对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;
}