Возможно, но в какой-то момент вам потребуется знать типы возвращаемых данных и параметров.
Вы можете использовать класс стирания типа, чтобы скрыть типы возвращаемых данных / параметров, а затем сохранить класс стирания типа. Достаточно наивной реализации, подобной этой,
#include <iostream>
#include <functional>
#include <unordered_map>
class MyLambda {
public:
MyLambda() = default;
virtual ~MyLambda() = default;
};
template <typename T>
class HiddenLambda : public MyLambda {
static_assert(std::integral_constant<T, false>::value, "Template parameter needs to be of function type.");
};
template <typename Ret, typename... Args>
class HiddenLambda<Ret(Args...)> : public MyLambda {
public:
HiddenLambda(std::function<Ret(Args...)> _fun) : fun_(_fun) { }
Ret operator() (Args... args) {return fun_(args...);}
private:
std::function<Ret(Args...)> fun_;
};
int main() {
std::unordered_map<std::string, std::shared_ptr<MyLambda>> my_lambdas;
my_lambdas.insert(std::make_pair("fun1", std::shared_ptr<MyLambda>(
new HiddenLambda<size_t(std::string)>(
[](std::string s) { return s.size(); } // <- lambda you want to store
)
)
));
my_lambdas.insert(std::make_pair("fun2", std::shared_ptr<MyLambda>(
new HiddenLambda<int(int)>(
[](int x) { return x * 5; } // <- lambda you want to store
)
)
));
auto it = my_lambdas.find("fun1");
/* Get the function we want! */
std::shared_ptr<MyLambda> a_lam = it->second;
/* Need to know the types to actually use it though */
HiddenLambda<size_t(std::string)>& actual_lam = dynamic_cast<HiddenLambda<size_t(std::string)>&>(*a_lam);
std::cout << actual_lam("how long is this string?") << "\n";
}
Если это то, что нам действительно нужно сделать, я предлагаю поискать различные методы удаления типов.
Я думаю, что проблема, которую вы пытаетесь решить, возможно, имеет более простое решение. Если бы вы могли дать более подробную информацию, возможно, мы могли бы помочь?
РЕДАКТИРОВАТЬ
Более подходящий пример для предоставленного вами кода ...
/* include above classes and includes */
void myfunc(int x, int y) {
std::cout << "uf1, " << x << ", " << y << std::endl;
}
int main() {
std::unordered_map<std::string, std::shared_ptr<MyLambda>> func_map;
func_map["userFun1"] = std::shared_ptr<MyLambda>(
new HiddenLambda<void(int, int)>( &myfunc ) // <- no args binded, notice the type = void(int,int)
);
func_map["userFun2"] = std::shared_ptr<MyLambda>(
new HiddenLambda<void(int)>( std::bind(myfunc, std::placeholders::_1, 5) ) // <- one args binded, notice the type = void(int)
);
func_map["userFun3"] = std::shared_ptr<MyLambda>(
new HiddenLambda<void()>( std::bind(myfunc, 1, 2)) // <- two args binded, notice the type = void()
);
/* we still need to know the type though,it will be either void(int, int), void(int) or void() */
HiddenLambda<void(int)>& actual_lam = dynamic_cast<HiddenLambda<void(int)>&>(*func_map["userFun2"]);
actual_lam(4);
}
РЕДАКТИРОВАТЬ V2
Это скорее догадка, чем что-либо еще. Я не уверен, стоит ли вам это делать (определенно не вне каких-то интересных экспериментов) или это будет работать. Вот возможный способ, если количество разных аргументов для разных функций известно и конечно. Это потребовало бы техники под названием «Вставка библиотеки», о которой я не очень разбираюсь.
Во-первых, в основной программе вы определяете это перечисление и заводскую функцию. Перечисление будет описывать каждый возможный диапазон параметров.
enum Types { kVOID, kINT_INT }; // <- verbosely define all the possible ones you would use
std::pair<Types, std::shared_ptr<MyLambda>> Factory(){
return
{
kVOID, /* <- some sensible default */
std::shared_ptr<MyLambda>(
new HiddenLambda<void()>( []{} )
)
};
}
В общей библиотеке должен быть предусмотрен переопределенный метод фабрики. Вот где я думаю, что для этого вам нужен вставщик.
std::pair<Types, std::shared_ptr<MyLambda>> Factory(){
return
{
kVOID_INT_INT,
std::shared_ptr<MyLambda>(
new HiddenLambda<void(int, int)>( [](int x, int y){ std::cout << (x + y);} )
)
};
}
Тогда основной метод будет выглядеть так:
int main() {
std::unordered_map<std::string, std::pair<Types, std::shared_ptr<MyLambda>>> func_map;
func_map.insert({"fun1", Factory()});
auto it = func_map.find("fun1");
/* always need to be able to deduce they type */
if (it->second.first == kVOID) {
CallHidden(*it->second.second);
}
else if (it->second.first == kINT_INT) {
CallHidden<int, int>(*it->second.second, 3, 4);
} else {
/* other ones you have statically typed */
}
}