我有这个设计:
class GenericData
{
};
class Data1 : public GenericData
{
};
class Data2 : public GenericData
{
};
class CompBase
{
public:
void process()
{
// inputs are check to make sure there number and order is correct
// Use them to automatically call the correct function
// What here ?
}
vector<GenericData> inputs;
};
class Comp1 : public CompBase
{
public:
void compute(Data1 input1, Data1 input2) { cout << "Comp1::compute(Data1 input1, Data1 input2)" << endl; }
void compute(Data2 input1, Data2 input2) { cout << "Comp1::compute(Data2 input1, Data2 input2)" << endl; }
void compute(Data1 input1, Data2 input2) { cout << "Comp1::compute(Data1 input1, Data2 input2)" << endl; }
};
class Comp2 : public CompBase
{
public:
void compute(Data1 input1) { cout << "Comp2::compute(Data1 input1)" << endl; }
void compute(Data2 input1) { cout << "Comp2::compute(Data2 input1)" << endl; }
};
具有以下约束条件:
以下是使用示例:
int main() {
Data1 d1; Data2 d2;
Comp1 c1; Comp2 c2;
c1.inputs = { d1, d1 };
c1.process(); // "Comp1::compute(Data1 input1, Data1 input2)"
c1.inputs = { d2, d2 };
c1.process(); // "Comp1::compute(Data2 input1, Data2 input2)"
c1.inputs = { d1, d2 };
c1.process(); // "Comp1::compute(Data1 input1, Data2 input2)"
vector<GenericComp> comps = { c1, c2 };
for (comp : comps)
{
comp.process();
}
return 0;
}
我有一个here的“工作”示例。
我尝试了不同的方法:CRTP,可变参数模板函数,currying和部分应用以及大量的谷歌搜索,但我被困在这里。
这些限制是否可能?如果是这样你怎么能这样做?
答案 0 :(得分:0)
谢谢你们的回答。 @Daniel Jour,你的帖子真的对我很有帮助,而且我做了一些修改以适应我的情况。
Here是一个适合我的更新示例。
#include <iostream>
#include <vector>
#include <map>
#include <functional>
#include <memory>
using namespace std;
class GenericData
{
public:
virtual ~GenericData() {};
};
class Data1 : public GenericData
{
public:
virtual ~Data1() {};
};
class Data2 : public GenericData
{
public:
virtual ~Data2() {};
};
class GenericComp
{
public:
virtual ~GenericComp() {};
vector<GenericData*> inputs;
};
class Comp1 : public GenericComp
{
public:
static bool compute(shared_ptr<Data1> const & input1, shared_ptr<Data1> const & input2) { cout << "Comp1::compute(Data1 input1, Data1 input2)" << (input2 ? "ok" : "null") << endl; return true; }
static bool compute(shared_ptr<Data2> const & input1, shared_ptr<Data2> const & input2) { cout << "Comp1::compute(Data2 input1, Data2 input2)" << endl; return true; }
static bool compute(shared_ptr<Data1> const & input1, shared_ptr<Data2> const & input2) { cout << "Comp1::compute(Data1 input1, Data2 input2)" << endl; return true; }
};
class Comp2 : public GenericComp
{
public:
static bool compute(shared_ptr<Data1> const & input1) { cout << "Comp2::compute(Data1 input1)" << endl; return true; }
static bool compute(shared_ptr<Data2> const & input1) { cout << "Comp2::compute(Data2 input1)" << endl; return true; }
};
// Arguments type to the function "interface"
using Arguments = std::vector<shared_ptr<GenericData>> const &;
// the interface
using Function = std::function<bool (Arguments)>;
// Base case of packing a function.
// If it's taking a vector and no more
// arguments, then there's nothing left to
// pack.
template<std::size_t N, typename Fn>
Function pack(Fn && fn)
{
return [fn = std::forward<decltype(fn)>(fn)] (Arguments arguments)
{
if (N != arguments.size())
{
throw std::string{"wrong number of arguments, expected "} +
std::to_string(N) +
std::string{" but got "} +
std::to_string(arguments.size());
}
return fn(arguments);
};
}
// pack a function to a function that takes
// it's arguments from a vector, one argument after
// the other.
template<std::size_t N, typename Arg, typename... Args, typename Fn>
Function pack(Fn && fn)
{
return pack<N+1, Args...>([fn = std::forward<decltype(fn)>(fn)] (Arguments arguments, Args const &... args)
{
try
{
return fn(arguments, arguments.at(N), args...);
}
catch (std::bad_cast const &)
{
throw std::string{"argument "} + std::to_string(N) + std::string{" has wrong type "};
}
});
}
// transform a function into one that takes its
// arguments from a vector
template<typename... Args, typename Fn>
Function pack_function(Fn && fn)
{
return pack<0, Args...>([fn = std::forward<decltype(fn)>(fn)] (Arguments arguments, Args const &... args) -> bool
{
return fn(args...);
});
}
int main() {
// Pack all the functions
std::map<std::string, Function> operations;
operations["Comp1_Data1_Data1"] = pack_function<shared_ptr<GenericData>, shared_ptr<GenericData>>([] (shared_ptr<GenericData> const & i1, shared_ptr<GenericData> const & i2)
{
return Comp1::compute(dynamic_pointer_cast<Data1>(i1), dynamic_pointer_cast<Data1>(i2));
});
operations["Comp1_Data2_Data2"] = pack_function<shared_ptr<GenericData>, shared_ptr<GenericData>>([] (shared_ptr<GenericData> const & i1, shared_ptr<GenericData> const & i2)
{
return Comp1::compute(dynamic_pointer_cast<Data2>(i1), dynamic_pointer_cast<Data2>(i2));
});
operations["Comp1_Data1_Data2"] = pack_function<shared_ptr<GenericData>, shared_ptr<GenericData>>([] (shared_ptr<GenericData> const & i1, shared_ptr<GenericData> const & i2)
{
return Comp1::compute(dynamic_pointer_cast<Data1>(i1), dynamic_pointer_cast<Data2>(i2));
});
operations["Comp2_Data1"] = pack_function<shared_ptr<GenericData>>([] (shared_ptr<GenericData> const & i1)
{
return Comp2::compute(dynamic_pointer_cast<Data1>(i1));
});
operations["Comp2_Data2"] = pack_function<shared_ptr<GenericData>>([] (shared_ptr<GenericData> const & i1)
{
return Comp2::compute(dynamic_pointer_cast<Data2>(i1));
});
// Create the possible inputs
vector<shared_ptr<GenericData>> data1_data1 { shared_ptr<Data1>(), shared_ptr<Data1>() };
vector<shared_ptr<GenericData>> data2_data2 { shared_ptr<Data2>(), shared_ptr<Data2>() };
vector<shared_ptr<GenericData>> data1_data2 { shared_ptr<Data1>(), shared_ptr<Data2>() };
vector<shared_ptr<GenericData>> data1 { shared_ptr<Data1>() };
vector<shared_ptr<GenericData>> data2 { shared_ptr<Data2>() };
// The calls !
operations["Comp1_Data1_Data1"](data1_data1);
operations["Comp1_Data2_Data2"](data2_data2);
operations["Comp1_Data1_Data2"](data1_data2);
operations["Comp2_Data1"](data1);
operations["Comp2_Data2"](data2);
// Wrong arguments
try
{
operations["Comp1_Data1_Data1"](data1);
}
catch (std::string const & e)
{
cout << e << endl;
}
try
{
operations["Comp2_Data1"](data1_data1);
}
catch (std::string const & e)
{
cout << e << endl;
}
return 0;
}