Ich versuche, eine Container-Klasse für unterschiedliche Funktionen zu implementieren, wo ich Funktionszeiger halten kann und verwenden Sie es später, diese Funktionen aufzurufen. Ich werde versuchen, mein Problem genauer zu beschreiben.Contaner für verschiedene Funktionen?
Als Beispiel habe ich zwei verschiedene Testfunktionen:
int func1(int a, int b) {
printf("func1 works! %i %i\n", a, b);
return 0;
}
void func2(double a, double b) {
printf("func2 works! %.2lf %.2lf\n", a, b);
}
und ich habe auch Reihe von Varianten, die Funktionsargumente hält:
std::vector<boost::variant<int, double>> args = {2.2, 3.3};
Ich habe beschlossen, meine eigene Funktors zu verwenden Klasse abgeleitet von einer Basisklasse (ich dachte über die Verwendung von virtuellen Methoden nach):
Auch ich ' habe beschlossen, einige Informationen über Funktion und ihre Argumente zu speichern:
struct TypeInfo {
int type_id; // for this example: 0 - int, 1 - double
template <class T>
void ObtainType() {
if (std::is_same<void, T>::value)
type_id = 0;
else if (std::is_same<int, T>::value)
type_id = 1;
else if (std::is_same<double, T>::value)
type_id = 2;
else
type_id = -1;
}
};
struct FunctionInfo {
public:
FunctionInfo() {}
FunctionInfo(BaseFunc *func, const TypeInfo& ret, std::vector<TypeInfo>& args) :
func_ptr(func), return_info(ret)
{
args_info.swap(args);
}
~FunctionInfo() {
delete func_ptr;
}
BaseFunc * func_ptr;
TypeInfo return_info;
std::vector<TypeInfo> args_info;
};
So, jetzt kann ich eine Container-Klasse definieren:
class Container {
private:
template <size_t n, typename... T>
void ObtainTypeImpl(size_t i, TypeInfo& t)
{
if (i == n)
t.ObtainType<std::tuple_element<n, std::tuple<T...>>::type>();
else if (n == sizeof...(T)-1)
throw std::out_of_range("Tuple element out of range.");
else
ObtainTypeImpl<(n < sizeof...(T)-1 ? n + 1 : 0), T...>(i, t);
}
template <typename... T>
void ObtainType(size_t i, TypeInfo& t)
{
return ObtainTypeImpl<0, T...>(i, t);
}
public:
template <class R, class ...Args>
void AddFunc(const std::string& str, R(*func)(Args...)) {
BaseFunc * func_ptr = new Func<R(Args...)>(func);
size_t arity = sizeof...(Args);
TypeInfo ret;
ret.ObtainType<R>();
std::vector<TypeInfo> args;
args.resize(arity);
for (size_t i = 0; i < arity; ++i)
{
ObtainType<Args...>(i, args[i]);
}
cont_[str] = FunctionInfo(func_ptr, ret, args);
}
void CallFunc(const std::string& func_name,
std::vector<boost::variant<int, double>>& args_vec) {
auto it = cont_.find(func_name);
if (it != cont_.end())
{
// ???????
// And here I stucked
}
}
private:
std::map<std::string, FunctionInfo> cont_;
};
Und dann stucked ich.
- Ich weiß nicht, wie man Funktionstyp Informationen von meinem struct bekommen :).
- Sie wissen nicht, wie Vektor-Varianten Argumente Liste zu konvertieren.
Vielleicht war mein Weg nicht in Ordnung? Kannst du irgendeine Lösung dieses Problems vorschlagen außer Skript-Engine wie Lua?
Ich denke, dass ich dieses Problem in Effektivere C++ gesehen von Scott Myers. Und er hat eine Lösung gefunden, glaube ich. – DumbCoder
Was sollte es tun, wenn die benannte Funktion verschiedene Argumente annimmt? Fehlschlagen oder die Werte auf den erwarteten Typ umwandeln? – Useless