在实现一个简单的记录器时

struct DebugOutput {
    DebugOutput(std::ostream& out = std::cerr) : m_Out(out) {}

    template<typename T>
    inline DebugOutput& operator <<(T&& value) {
        m_Out << value;
        return *this;
    }
private:
    std::ostream& m_Out;
};

我发现universal reference不会捕获std::endl
DebugOutput dbg;
dgb << std::endl;

我找到了这个this post,它说明您需要在结构中添加一个重载函数,该结构专门采用了函数指针签名,即:
typedef std::ostream& (*StandardEndLine)(std::ostream&);
inline DebugOutput& operator<<(StandardEndLine manip) {
    return *this;
}

为什么函数指针没有被通用引用捕获?它不是int还是void*类型吗?

最佳答案

函数(指针)可以绑定(bind)到通用引用。例:

void f(int) {}

template <typename T>
void foo(T&&) {}

foo(f); // OK

但是,重载函数不能。也就是说,如果您添加f的第二次重载,请说,
void f(double) {}

调用foo(f)将失败。

专心于编译器。需要将f传递给foo,并且有两个名为f的函数,每个函数具有不同的类型。如果我们告知类型,则编译器可以毫不含糊地选择正确的f。例如,
foo(static_cast<void (*)(int)>(f));

可以正常编译,并将void f(int)(在函数到指针转换之后)传递给foo

但是,我们没有通知类型。我们宁愿要求编译器进行推断。

f相似,相同的参数适用于std::endl,因为这是一个函数模板,因此,名称std::endl表示一组函数,它们的名称相同但类型不同。

现在,您可以看到导致错误的原因是我们提供了一个重载集并要求类型推断。因此,这并不是通用引用书所特有的。
std::cout << std::endl之所以有效,是因为basic_ostream::operator <<不是模板,并且不会尝试推断所传递参数的类型。这个函数需要一种特殊类型的std::endl

07-24 09:38
查看更多