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


在实现简单的记录器时

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

我发现 std::endl 将不被捕获 普遍参考

DebugOutput dbg;
dgb << std::endl;

我找到了这个 这个帖子 这解释了你需要在结构中添加一个特别是函数指针签名的重载函数,即:

typedef std::ostream& (*StandardEndLine)(std::ostream&);
inline DebugOutput& operator<<(StandardEndLine manip) {
    return *this;
}

为什么通用引用不捕获函数指针?这不是一种类型 int 要么 void* ?


3356
2017-09-27 09:20


起源

这是一个模板/重载。 - Xeo
stackoverflow.com/a/1136617/46642 - R. Martinho Fernandes
可能重复 当重载operator <<时,std :: endl是未知类型 - Xeo
谢谢@ R.MartinhoFernandes我错过了这个评论,这完全解释了它。 - Guillaume Chatelet


答案:


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

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


12
2017-09-27 10:05



很清楚!谢谢@ cassio-neri :) - Guillaume Chatelet