从 std::function 参数类型推导出模板参数

时间:2021-01-18 16:40:00

标签: c++ c++20

为什么下面的类 A 不能在下面的代码中推导出它的模板参数:

#include <functional>

template <class... Ts>
class A
{
public:

    using Func = std::function<void(std::decay_t<Ts>...)>;

    A(Func func) : m_func(func)
    {
    }

private:

    Func m_func;
};

int main()
{
    //compiles
    A<int, bool> a([](int, bool) {});

    //does not compile with error 'class template argument deduction failed'
    A b([](int, bool) {});

    return 0;
}

该类有一个 Func 类型的数据成员,需要知道其参数的类型。如何编译?

EDIT1:

我能够使用 std::tuple 进行编译:

#include <tuple>

template <class... Ts>
class A
{
public:

    using Func = std::tuple<Ts...>;

    constexpr A(Func func) : m_func(func)
    {
    }

private:

    Func m_func;
};

int main()
{
    std::tuple<int, bool> t;
    
    //compiles
    A<int, bool> a(t);

    //do not compile with error 'class template argument deduction failed'
    A b(t);

    return 0;
}

2 个答案:

答案 0 :(得分:1)

两个问题。

  1. template argument deduction 中不会考虑隐式转换(从 lambda 到 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="container"> <div class="toggle"> <a href="#" class="show_div">Show</a> <a href="#" class="hide_div">Hide</a> </div> <div class="show_hide">Text</div> <div class="show_hide">Text2</div> <div class="show_hide">Text3</div> <div class="show_hide">Text4</div> <div class="show_hide">Text5</div> </div> <div class="container"> <div class="toggle"> <a href="#" class="show_div">Show</a> <a href="#" class="hide_div">Hide</a> </div> <div class="show_hide">Text</div> <div class="show_hide">Text2</div> <div class="show_hide">Text3</div> <div class="show_hide">Text4</div> <div class="show_hide">Text5</div> </div>);导致扣减失败。

  2. std::function 的存在导致 non-deduced context;那么就不能推导出 std::decay_t

以下代码编译。

Ts

答案 1 :(得分:0)

模板参数推导传统上是函数调用表达式的专有特性。在 C++17 中引入 deduction guides 之前,无法从构造函数调用推导出类模板的模板参数。这样,您就可以明确指定如何从构造函数调用中推导出类的模板参数。

template <class... Ts>
class A
{
public:

    using Func = std::tuple<Ts...>;

    constexpr A(Func func) : m_func(func)
    {
    }

private:

    Func m_func;
};

template< class... Ts >
A(std::tuple< Ts... >) -> A< Ts... >;

int main()
{
    std::tuple<int, bool> t;
    
    A<int, bool> a(t);

    A b(t); // deduces int, bool types from t

    return 0;
}

使用推导指南从 lambda 推导函数调用签名可能有问题。 lambda 函数没有定义与其签名对应的类型。如果 lambda 是多态的(即在其参数列表中使用 auto),那么首先就不可能定义这种类型。并且可以使用与其签名不同的参数来调用函数,因此可能有多个不同的参数类型集,该函数可通过这些参数类型调用。在这种情况下,您很可能必须明确指定参数类型。

仍然可以从函数指针中推导出模板参数:

template< class R, class... Ts >
A(R (*)(Ts...)) -> A< Ts... >;