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

23 浏览
0 Comments

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

如果取消注释第一个操作符定义,这段代码将能够编译和运行:\n

#include 
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
logger &operator<<(logger &l, const T &t) {
    l.loggingStream << t;
    return l;
}
int main() {
    logger l(std::cout);
    l << "Hello" << std::endl;
    return 0;
}

\n加上注释后会出现以下错误:\n

error: no match for ‘operator<<’ (operand types are ‘logger’ and ‘’)

\n为什么我需要提供一个非模板重载来处理 `endl`?

0
0 Comments

问题是,为什么模板操作符<<不能推断出std::endl的类型,以及解决方法。

原因是,作为一个函数模板,std::endl是一个重载集,涉及到模板参数推断;而模板参数推断不能在重载集上工作(除非重载集只包含一个函数)。

为了说明这一点,考虑下面的例子:

template
void functor(Function f)
{ 
    f(0); 
}
void g(float) {}
void g(double) {}
functor(g);

在这个例子中,没有理由偏好其中一个版本的g,除非你明确地特化functor(functor(f)是可以的),否则模板参数推断必定失败。

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

解决方法是,在使用模板操作符<<时,显式指定std::endl的类型,例如:

std::cout << std::endl>; 

或者使用具体的类型而不是模板,例如:

std::cout << '\n';

0
0 Comments

为什么模板操作符<<不能推断std::endl?

在C++中,std::endl是一个模板。当我们有第一个重载的时候,它的参数可以通过匹配函数指针来推断。因为这是类型自动推导的一种情况。

但是,在只有operator<<模板的情况下,有什么可以推断的呢?这两个模板都需要推断它们的参数。

为了更好地理解这个问题,让我们先来看一下C++中的模板和类型自动推导。

模板是一种通用的代码模式,它允许在不指定具体类型的情况下编写函数或类。它们允许我们写出适用于多种类型的代码,从而提高代码的重用性和灵活性。

类型自动推导(Type Argument Deduction,TAD)是C++中的一种特性,它允许编译器根据函数调用的参数来推断模板函数的模板参数类型。这使得我们可以在调用函数时省略模板参数类型,从而简化代码。

现在让我们回到我们的问题上来。为什么模板操作符<<不能推断std::endl的参数类型?

首先,让我们看一下std::endl的定义:

template

std::basic_ostream& endl(std::basic_ostream& os);

从上面的定义可以看出,std::endl是一个函数模板,它接受一个std::basic_ostream对象的引用并返回该对象的引用。然而,在只有operator<<模板的情况下,编译器无法根据这个定义来推断std::endl的参数类型。

为了解决这个问题,我们可以将std::endl的参数类型指定为模板参数,然后将其传递给operator<<模板。这样,编译器就可以根据传递给operator<<的参数类型来推断std::endl的参数类型。

下面是一个示例代码:

// 模板操作符<<
template 
std::ostream& operator<<(std::ostream& os, const T& obj)
{
    os << obj;
    return os;
}
// 使用模板操作符<<
template 
void print(const T& obj)
{
    std::cout << obj << std::endl;
}
int main()
{
    int num = 42;
    print(num);
    return 0;
}

在上面的示例代码中,我们将std::endl的参数类型指定为模板参数T,并将其传递给operator<<模板。这样,编译器就能够根据传递给print函数的参数类型来推断std::endl的参数类型。

总结一下,模板操作符<<无法推断std::endl的参数类型是因为它们都是模板,需要根据上下文来推断参数类型。为了解决这个问题,我们可以将std::endl的参数类型指定为模板参数,并将其传递给operator<<模板。这样,编译器就可以根据上下文来推断参数类型。

0