c++ - C++ lambdas 和模板的交互

标签 c++ templates lambda c++17

这个问题在这里已经有了答案:





C++11 does not deduce type when std::function or lambda functions are involved

(3 个回答)


去年关闭。




我正在尝试围绕 C++ lambda 表达式和模板的交互进行思考。

此代码按我的预期工作:

#include <iostream>

int bar (int x, int (* f) (int))
{
    return f (x);
}

double bar (double x, double (* f) (double))
{
    return f (x);
}

int main ()
{
    std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
    std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;

    return 0;
}

这样做也是如此:
#include <iostream>
#include <functional>

int bar (int x, std::function<int (int)> f)
{
    return f (x);
}

double bar (double x, std::function<double (double)> f)
{
    return f (x);
}

int main ()
{
    std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
    std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;

    return 0;
}

到现在为止还挺好。但以下示例均无法编译:
#include <iostream>

template <typename T>
T bar (T x, T (* f) (T))
{
    return f (x);
}

int main ()
{
    std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
    std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;

    return 0;
}


#include <iostream>
#include <functional>

template <typename T>
T bar (T x, std::function <T (T)> f)
{
    return f (x);
}

int main ()
{
    std::cout << bar (16, [] (int x) -> int { return x * x; }) << std::endl;
    std::cout << bar (1.2, [] (double x) -> double { return x * x; }) << std::endl;

    return 0;
}

GCC 版本 8.3.0(使用 -std=c++17)给出了一条错误消息:
no matching function for call to 'bar(int, main()::<lambda(int)>' (and
another for the "double" version) and "template argument
deduction/substitution failed: main()::<lambda(int)> is not derived
from std::function<T(T)>" (for the second failing example).

但是,此任务有效:
std::function<int (int)> f = [] (int x) -> int { return x * x; };

任何人都可以为我照亮吗? (显然,这不是实用的代码。这只是学习的尝试。)

最佳答案

问题是在 template argument deduction 中不会考虑隐式转换(从 lambda 到函数指针或 std::function) ;然后在您的第三个和第四个样本类型扣除 T第二个函数参数(即 lambda)失败。

Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.



在这种情况下 T只能从第一个函数参数中推导出来;你可以用 non-deduced context 声明第二个, 将其排除在扣除范围之外。

例如
template <typename T>
T bar (T x, std::type_identity_t<T (*) (T)> f)
{
    return f (x);
}

template <typename T>
T bar (T x, std::type_identity_t<std::function <T (T)>> f)
{
    return f (x);
}

PS: std::type_identity 可以从 C++20 获得,在此之前您可以自己制作一个,这并不困难。

LIVE

关于c++ - C++ lambdas 和模板的交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61626853/

相关文章:

c++ - GCC:在 "control reaches end of non-void function"中断编译

c++ - 在 netbeans 中将 C++ 代码输出为汇编语言

java - lambda函数如何成为Comparator的compare()方法

c++ - Qt 使用鼠标在线性布局中调整小部件的大小

c++ - 根据 C++11 中的模板参数选择数组大小?

html - Go template/html 迭代从结构生成表

c++编译错误涉及方法重载的2个模板函数

java - 链接 lambda 函数

使用 lambda 进行 C++ 模板参数推导

c++ - 用于跟踪 sibling 的 QObject 指针的静态 QList?