如何获取可调用类型的签名?

时间:2019-02-15 16:59:57

标签: c++ templates stl c++17 template-meta-programming

我想构建一个漂亮的现代界面来构建计算树,如下所示:

auto [F, G] = calcs.emplace(
        [](int a, int b){ return a + b; },
        [](){ return 4; }
    );

我从taskflow那里得到了启发,但是在这里我们可能还会添加参数和返回类型,这是一个问题:如何为给定的 Callable <推断基础存储的类型? / em>对象,以及如何将它们存储在集合中?是否有可能完全创建具有当前语言功能的简单api?

我用谷歌搜索了几个小时,看起来返回类型是较小的问题,但是我不知道这些参数。

1 个答案:

答案 0 :(得分:0)

问::如何获得签名?

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())>;

问::如何在集合中存储可调用对象?

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;
};

然后,编写一个实现此接口的模板类,该模板类将为每个lambda参数实例化。实际上,您在calcs对象中存储了std::vector<std::unique_ptr<CallableI>>