为什么模板运算符<<不能推断出std :: endl?

时间:2019-03-06 17:44:33

标签: c++ templates iostream iomanip

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

#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

2 个答案:

答案 0 :(得分:1)

因为std::endl作为函数模板,是关于模板自变量推导的重载集;和模板参数推论不适用于重载集(除非它当然只包含一个函数)。

为说明,请考虑:

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

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

functor(g);

没有理由偏爱g的一个版本,除非您明确地专门化functorfunctor<void(float)>(f)很好),否则模板参数推导必须失败。

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

答案 1 :(得分:1)

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

使用 just operator<<模板,可以从中推论出什么?这两个模板都需要推论其参数。