【问题标题】:lambda expression and template deduction against std::function: why this works?针对 std::function 的 lambda 表达式和模板推导:为什么会这样?
【发布时间】:2018-08-10 12:53:20
【问题描述】:

我的问题与这个问题有些相关: Lambdas and std::function。请阅读此问题及其接受的答案。

所以,公认的答案是,下面的代码使得模板参数推导 lambda 成功,但为什么呢?

template<class T>
struct Identity{
  typedef T type;//why this helps?
};

template<typename BaseT>
vector<BaseT> findMatches(vector<BaseT> search, 
    typename Identity<function<bool (const BaseT &)>>::type func)
{
    vector<BaseT> tmp;

    for(auto item : search)
    {
        if( func(item) )
        {
            tmp.push_back(item);
        }
    }

    return tmp;
}

void Lambdas()
{
    vector<int> testv = { 1, 2, 3, 4, 5, 6, 7 };

    auto result = findMatches(testv, [] (const int &x) { return x % 2 == 0; });//lambda here.

    for(auto i : result)
    {
        cout << i << endl;
    }
}

int main(int argc, char* argv[])
{

    Lambdas();

    return EXIT_SUCCESS;
}

上面的代码可以运行,但我不知道为什么。首先,我知道 BaseT 的模板推导不会发生在 lambda 中,因为这是一个不可推导的上下文 (Identify&lt;function&lt;bool (const BaseT &amp;)&gt;&gt;::type)。相反,BaseTtestv 推导出为int,并且模板参数替换发生在Identity&lt;function&lt;bool (const BaseT &amp;)&gt;&gt;::type 中。

但是接下来呢?替换后,Identity&lt;function&lt;bool (const BaseT &amp;)&gt;&gt;::type 变成了function&lt;bool (const BaseT &amp;)&gt;,但不是 lambda 表达式不是那种类型,并且模板参数推导中不会发生转换(虽然这里是模板参数替换)?

感谢您的解释! 附言我似乎知道编译器会为每个 lambda 表达式生成唯一命名的类。那么为什么 lambda 可以匹配 function&lt;bool (const BaseT &amp;)&gt; 呢?

【问题讨论】:

    标签: c++ lambda std-function template-argument-deduction


    【解决方案1】:

    但是接下来呢?替换后Identity&lt;function&lt;bool (const BaseT &amp;)&gt;&gt;::type变成function&lt;bool (const BaseT &amp;)&gt;,但是不是lambda表达式不是那个类型的,而且模板参数推导不会发生转换(虽然这里是模板参数替换)?

    您是正确的,在模板参数推导期间没有 subisitution,但一旦完成,我们将函数调用视为调用实例化函数。 这意味着 Identity&lt;function&lt;bool (const BaseT &amp;)&gt;&gt;::type 已替换为 function&lt;bool (const BaseT &amp;)&gt; 您正在调用的实例化函数是:

    vector<int> findMatches(vector<int> search, function<bool (const int&)> func)
    

    由于它采用具体的function&lt;bool (const int&amp;)&gt;,因此 lambda 可用于构造 func

    【讨论】:

    • 所以它可以工作,因为在函数模板被实例化后,lambda表达式在函数重载阶段(阶段)隐式转换为lambda?所以过程是模板参数推导 -> 模板参数替换 -> 重载解析(转换发生在哪里?)
    • @HanXIAO 基本上。请记住,函数模板不是函数,它是如何制作的秘诀。因此,一旦您推断出模板参数,那么您就可以剔除一个使用实际推断类型的函数。您实际调用的正是这个函数,因为它的真实类型为 functional&lt;bool (const int&amp;)&gt;,所以可以转换 lambda。
    【解决方案2】:

    这是因为func 参数的类型是推导出来的。 通过使用外部特征类Idendity,代码使func 参数的类型依赖于BaseT 模板参数,将其转换为非推断上下文。

    因此,会发生BaseT 被推导出为search 参数和func 的事实上的类型,依赖于BaseT,变得已知。最后,您的 lambda 可以隐式转换为所需的 std::function&lt;bool(int const&amp;)&gt; 类型。

    如果你省略这个技巧,使func 的类型依赖于BaseT,例如:

    template<typename BaseT>
    vector<BaseT> findMatches(vector<BaseT> search, 
         function<bool (const BaseT &)> func)
    

    然后,func 的模板参数推导也会发生,并会产生编译器错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-20
      • 2014-06-24
      相关资源
      最近更新 更多