非常具体的子类方法调用
Very specific sub-class method call
我有这样的设计:
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; }
};
具有以下约束:
- 计算函数必须从GenericComp调用,但不能在这里全部声明,因为会有两个多(Data1,2和comp1,2只是例子)
- I 必须能够有一个CompBase 的集合
- 计算函数必须不必须检查它们的输入(即传递相同的结构是不可能的)
- 代码必须足够通用,以便轻松添加其他数据,比较和计算
下面是一个使用的例子:
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;
}
我这里有一个"工作"的例子。
我尝试了不同的方法:CRTP,可变模板函数,柯里化和部分应用程序和大量的谷歌搜索,但我被困在这里。
在这些约束条件下是可能的吗?
谢谢大家的回答。@Daniel Jour,你的帖子真的帮助了我,我有一些修改来适应我的情况。
这是一个更新的例子,将为我工作。
#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;
}
相关文章:
- 使用用户定义的参数调用future/async并调用类方法
- 重载类方法的不明确调用
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 从基类实例调用派生类方法而不进行强制转换
- 派生类调用父类的方法,该方法调用重写的虚拟方法调用错误的方法
- 函数从唯一代码调用正确的子类方法
- C++ |DLL / EXE - 如何从导出的类调用另一个类方法?
- C++:从属性类调用顶级类方法
- 指向类方法调用的指针
- 有没有办法从同一类中的函子调用类方法?
- 有没有办法禁止派生类中的基类方法调用?
- 从类方法调用命名空间中名为 Same 的函数时,重载解析失败
- 我可以从析构函数的类方法调用它吗
- C++指向类方法调用的指针
- 基类方法调用派生类方法,任何可能的解决方案
- 从基类方法调用虚拟方法
- 非常具体的子类方法调用
- 类方法调用是否会在for循环中进行优化
- 使用具有相同声明的类方法调用全局函数
- 如何在c++中实现抽象类,同时允许子类方法调用