为什么通用引用不捕获函数指针?

Gui*_*let 11 c++ c++11

在实现简单的记录器时

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;
};
Run Code Online (Sandbox Code Playgroud)

我发现std::endl不会被通用引用捕获.

DebugOutput dbg;
dgb << std::endl;
Run Code Online (Sandbox Code Playgroud)

我发现这篇文章解释了你需要在结构中添加一个特别是函数指针签名的重载函数,即:

typedef std::ostream& (*StandardEndLine)(std::ostream&);
inline DebugOutput& operator<<(StandardEndLine manip) {
    return *this;
}
Run Code Online (Sandbox Code Playgroud)

为什么通用引用不捕获函数指针?是不是类型intvoid*

Cas*_*eri 12

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

void f(int) {}

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

foo(f); // OK
Run Code Online (Sandbox Code Playgroud)

但是,重载功能不能.也就是说,如果你添加第二个重载f,比方说,

void f(double) {}
Run Code Online (Sandbox Code Playgroud)

电话foo(f)会失败.

把自己放在编译器鞋上.它需要传递ffoo并且有两个函数,f每个函数都有不同的类型.如果我们通知类型,那么编译器可以毫不含糊地选择正确的f.例如,

foo(static_cast<void (*)(int)>(f));
Run Code Online (Sandbox Code Playgroud)

编译好并将void f(int)(在函数到指针转换后)传递给foo.

但是,我们没有告知该类型.我们宁愿要求编译器推断它.

与此类似f,相同的参数适用于std::endl因为这是一个函数模板,因此,名称std::endl表示一组函数,所有函数都具有相同的名称但不同的类型.

现在,您可以看到错误的原因是我们提供了一个重载集并要求类型推导.因此,这不是普遍的参考.

std::cout << std::endl因为basic_ostream::operator <<不是模板而且不试图推断传递的参数的类型.这是一种采用一种特殊类型的函数std::endl.