【问题标题】:Why does the following `std::transform` example need a function pointer instead of a function object?为什么以下 `std::transform` 示例需要函数指针而不是函数对象?
【发布时间】:2019-10-31 06:46:32
【问题描述】:

函数模板std::transform() 采用一个范围,使用运算符对它进行逐个操作,并将结果保存在另一个范围中。在下面的示例中,该函数采用名为nl 的通用std::initializer_list 并使用(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

【问题讨论】:

  • 请注意,您不能在 C++20 及更高版本的标准库中获取函数的地址:en.cppreference.com/w/cpp/language/…。此代码将具有未指定的行为或可能无法编译。相反,你应该写[](int i) { return std::to_string(i); };,这很糟糕,但有人建议让它变得更好。
  • std::to_string 有很多重载,所以 std::to_string 单独并不能唯一标识一个函数。见stackoverflow.com/questions/2942426/…
  • 因为函子可以是带有operator()任何对象,并且它无法知道它应该使用哪个模板实例化或重载。
  • 函数to_string 有重载,通过将其转换为函数指针,您可以告诉编译器选择哪一个。 (见godbolt.org/z/nQrzWc,注释掉goo::foo的重载)

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


【解决方案1】:

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);});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 2018-03-23
    相关资源
    最近更新 更多