Q: Как получить подпись?
A: Путем сопоставления с шаблоном по operator()
методу вызова, например:
template <class TMethodType>
struct ReadSignature;
// Const specialization
template <class TReturnType, class TClass, class ... TArgsTypes>
struct ReadSignature<TReturnType(TClass::*)(TArgsTypes...) const> {
using ReturnType = TReturnType;
using Class = TClass;
using Args = std::tuple<TArgsTypes...>;
static constexpr bool is_const = true;
};
// Non-const specialization
// This is for mutable lambdas, e.g. []() mutable {}
template <class TReturnType, class TClass, class ... TArgsTypes>
struct ReadSignature<TReturnType(TClass::*)(TArgsTypes...)> {
using ReturnType = TReturnType;
using Class = TClass;
using Args = std::tuple<TArgsTypes...>;
static constexpr bool is_const = false;
};
Вы используете это так:
auto callable = [](int x, int y) { return x + y; };
using Class = decltype(callable);
using Signature = ReadSignature<decltype(&Class::operator())>;
Q: Как хранить вызываемые элементы в коллекции?
A: ВыНужно будет стереть типы так или иначе.Для вызываемых объектов создание интерфейса-обертки кажется естественным.Например, что-то вроде этого:
class CallableI {
virtual ~CallableI() = default;
virtual std::any call(const std::vector<std::any>& args) = 0;
// For type checking:
virtual size_t arg_count() = 0;
virtual std::type_info get_arg_type_info(size_t arg_index) = 0;
virtual std::type_info get_return_type_info() = 0;
};
Затем вы пишете шаблонный класс, реализующий этот интерфейс, который будет создан для каждого лямбда-аргумента.В вашем calcs
объекте вы на самом деле храните std::vector<std::unique_ptr<CallableI>>
.