为什么模板运算符<<不推断 std::endl?[复制]

Why doesn't template operator<< deduce std::endl? [duplicate]

提问人:spraff 提问时间:3/7/2019 更新时间:3/7/2019 访问量:147

问:

如果您取消注释第一个运算符定义,这将编译并运行:

#include <iostream>

struct logger
{
    std::ostream &loggingStream;
    logger(std::ostream &ls) : loggingStream(ls) {}

};

/*
logger &operator<<(logger &l, std::ostream & (*manip)(std::ostream &)) {
    manip(l.loggingStream);
    return l;
}
*/

template<typename T>
logger &operator<<(logger &l, const T &t) {
    l.loggingStream << t;
    return l;
}

int main() {
    logger l(std::cout);

    l << "Hello" << std::endl;
    return 0;
}

有了评论:

error: no match for ‘operator<<’ (operand types are ‘logger’ and ‘<unresolved overloaded function type>’)

为什么我需要提供非模板重载来处理?endl

C++ 模板 IOSTREAM IOManip

评论

0赞 AProgrammer 3/7/2019
1/ 参见 stackoverflow.com/q/1134388/136208 2/ 编写自定义 streambuf 是 IO 子系统为此类扩展而设计的方式

答:

1赞 YSC 3/7/2019 #1

因为,作为一个函数模板,std::endl 是关于模板参数推导的重载集;模板参数推导不能在重载集上起作用(当然,除非它只包含一个函数)。

为了说明这一点,请考虑:

template<class Function>
void functor(Function f)
{ f(0); }

void g(float) {}
void g(double) {}

functor(g);

没有理由偏袒一个版本而不是另一个版本,除非您明确专业化(很好),否则模板参数推导必须失败。gfunctorfunctor<void(float)>(f)

如果是模板,也是如此:http://coliru.stacked-crooked.com/a/8e27a45bbeedd979g

1赞 StoryTeller - Unslander Monica 3/7/2019 #2

std::endl本身就是一个模板。当您遇到第一个重载时,可以通过与函数指针匹配来推导其参数。因为这是 TAD 发生的一个例子。

凭模板,有什么可以推断的?这两个模板都需要推导它们的参数。operator<<