创建一个参数有限的std :: function类型

sky*_*ack 6 c++ templates variadic-templates std-function c++14

鉴于可调用函数的类型C,我想在编译时得到一个std::function; 其类型:

  • 具有相同的返回类型的函数 C
  • 参数类型是N函数的第一个参数类型C

这意味着,对于给定类型void(int, char, double)和给定N,函数的类型是:

  • N = 1 =>结果类型: std::function<void(int)>
  • N = 2 =>结果类型: std::function<void(int, char)>
  • N = 3 =>结果类型: std::function<void(int, char, double)>
  • N > 3 =>编译时错误

例:

template<std::size_t N, typename R, typename... A>
constexpr auto get() {
    return /*(magically somehow)*/ std::function<R(FirstNFromA...)>
}

template<std::size_t N, typename R, typename... A>
struct S {
    using func = decltype(get<N, R, A...>());
};
Run Code Online (Sandbox Code Playgroud)

sky*_*ack 6

它遵循可能的解决方案:

#include <tuple>
#include <utility>
#include <functional>
#include <type_traits>

template<
    typename R,
    typename... A,
    std::size_t... I,
    std::enable_if_t<(sizeof...(I)<=sizeof...(A))>* = nullptr
> constexpr auto
get(std::integer_sequence<std::size_t, I...>) {
    return std::function<R(std::tuple_element_t<I, std::tuple<A...>>...)>{};
}

template<std::size_t, typename>
struct FuncType;

template<std::size_t N, typename R, typename... A>
struct FuncType<N, R(A...)> {
    using Type = decltype(get<R, A...>(std::make_index_sequence<N>{}));
};

int main() {
    static_assert(
        std::is_same<
            FuncType<2, void(int, char, double, int)>::Type,
            std::function<void(int, char)>
        >::value,
        "!"
    );
}
Run Code Online (Sandbox Code Playgroud)

基本思想是使用a tuple和那些属于标准模板库的实用程序(作为示例std::tuple_element),将它们与放置在正确位置的包扩展混合在一起.
为此,我使用了一个constexpr返回std::function给定类型的空对象的函数.然后,函数的类型通过a获取,decltypeFuncType使用别名作为对象的类型导出.
一切都在编译时进行.
为了推导出该函数的正确类型,我使用了一个众所周知的模式,它std::integer_sequence通过扩展索引来实现并实际解包元组的类型.