为什么下面的`std :: transform`示例需要一个函数指针而不是一个函数对象?

时间:2019-06-17 16:21:23

标签: c++ c++11 casting std function-pointers

功能模板std::transform()包含一个范围,并用运算符对其进行逐个操作,然后将结果保存在另一个范围中。在下面的示例中,该函数采用名为std::initializer_list的通用nl并使用(std::string (*)(T)) std::to_string在其上进行操作,以将其所有条目转换为字符串,然后将结果存储在一个称为字符串的数组中buffer

class num_list
{
public:
    template<typename T>
    num_list(std::initializer_list<T> nl):
        size{nl.size()},
        buffer(new std::string[size])
    {
        std::transform(nl.begin(), nl.end(), // input sequence
        buffer,                              // output result
        (std::string (*)(T))std::to_string); // unary operator
    }
    //...
private:
    std::size_t size;
    std::string * buffer;
};

我想知道为什么我们需要将std::to_string转换成函数指针才能起作用。如果将强制类型转换为指针指向函数类型(std::string (*)(T)),为什么代码无法使用C ++ 11编译?我无法破译编译器引发的抱怨。

error: no instance of overloaded function "std::transform" matches the argument list

1 个答案:

答案 0 :(得分:5)

std::transform是一个功能模板,它通过模板参数类型获取功能对象。由于类型是模板参数,因此必须推导它。 std::to_string是重载函数,因此当您尝试推导其类型时,会得到多个结果。由于推论中没有其他内容可以帮助缩小类型,因此编译器将无法推导std::to_string的类型,您会得到一个错误。

当您将std::to_string转换为std::string (*)(T)时,现在只有一个类型可以让编译器推断出该类型,并且可以成功编译。

您可以使用通用lambda代替强制转换,而不是像

那样转发至std::to_string
std::transform(nl.begin(), nl.end(), // input sequence
buffer,                              // output result
([](auto&& val){ return std::to_string(val);});

,但这至少需要C ++ 14。对于C ++ 11,您可以使用T作为参数类型,例如

std::transform(nl.begin(), nl.end(), // input sequence
buffer,                              // output result
([](const T& val){ return std::to_string(val);});