std::transform 具有重载的转换函数

std::transform with an overloaded conversion function

我想从一个容器 c 转换所有对象 - 类型为 char - 并将结果 - 类型为 foo - 存储在一个容器中不同的容器 v。所需的转换函数是一个重载函数 - 称之为 to_foo.

考虑以下 example

#include <algorithm>
#include <vector>    

struct foo {};

foo to_foo(char) { return {}; }
foo to_foo(int) { return {}; }

int main()
{
    std::array<char, 1> c;
    std::vector<foo> v(c.size());

//  cannot determine which instance of overloaded function "to_foo" is intended:
    std::transform(c.begin(), c.end(), v.begin(), to_foo);

//  ok:
    std::transform(c.begin(), c.end(), v.begin(), [](auto const& ch) { return to_foo(ch); });
}

虽然我觉得在第一次转换中编译器不知道它应该采用 to_foo 的哪个重载(另一方面,他不能从 value_type 的迭代器?),我不明白为什么他能够在第二次转换中这样做。这里发生了什么?

你必须通过强制转换 to_foo:

明确地告诉它使用哪个重载
std::transform(c.begin(), c.end(), v.begin(), static_cast<foo (*)(char)>(to_foo));

std::transform 的一元运算参数的类型与用于迭代器的模板参数不同。因此它必须使用您传递的值的类型来推断模板参数。 to_foo 的类型不明确,因此无法完成该过程。将函数指针转换为特定的重载类型使其明确无误。


在第二种形式中,lambda 是一个可调用对象,使用 auto 使对象的 () 运算符成为函数模板:

struct NamelessGenericLambda {
    template <typename T>
    foo operator ()(T const& ch) { return to_foo(ch); }
};
std::transform(c.begin(), c.end(), v.begin(), NamelessGenericLambda{});

类型明确,可以实例化std::transform模板。

然后在 std::transform 中的某处,它将尝试通过传递 char 来实例化 operator () 模板。因为它传递了明确的类型,所以编译器推断 ch 是一个字符。然后它使用常规重载决策选择 to_foo 的正确重载。