c++ - 为什么运算符 << 不明确?

标签 c++ overloading

我在全局范围内定义了一个函数模板

template<class T>
inline std::ostream& operator<<(std::ostream& os, T const& t)
{       
    return os;
}

然后

std::cout << "\n";

由于不明确而无法编译。我认为是函数重载,编译可以解决它,并为char const*选择更具体的版本。为什么不能编译?

最佳答案

您的 operator<< 版本这里是根据一个参数进行模板化的,标准提供的版本也是如此。

问题在于您的版本(我们将其称为函数a)是根据一个参数进行模板化的:

template<class T>
inline std::ostream& operator<<(std::ostream& os, T const& t)
{       
    return os;
}

来自cppreference ,您可以看到 const char* 的标准过载(我们称之为b)是在另一个上模板化的:

template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,  
                                        const char* s );

您可以通过创建 operator<< 版本来获得您期望的行为对第一个参数使用相同的模板参数(这个是c):

template<class T, class CharT, class Traits>
inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, T const& t)
{       
        return os;
}

编译顺利,如您所见on coliru .

这是因为在选择具有多个候选模板函数的重载时,模板重载选择会选择最专业的模板。

具体来说,首先对模板进行转换:

[temp.func.order]:

  1. Partial ordering selects which of two function templates is more specialized than the other by transforming each template in turn (see next paragraph) and performing template argument deduction using the function type. The deduction process determines whether one of the templates is more specialized than the other. If so, the more specialized template is the one chosen by the partial ordering process.

  2. To produce the transformed template, for each type, non-type, or template template parameter (including template parameter packs thereof) synthesize a unique type, value, or class template respectively and substitute it for each occurrence of that parameter in the function type of the template. [ Note: The type replacing the placeholder in the type of the value synthesized for a non-type template parameter is also a unique synthesized type.  — end note ] ...

[temp.deduct.partial]:

  1. Two sets of types are used to determine the partial ordering. For each of the templates involved there is the original function type and the transformed function type. [ Note: The creation of the transformed type is described in [temp.func.order].  — end note ] The deduction process uses the transformed type as the argument template and the original type of the other template as the parameter template. This process is done twice for each type involved in the partial ordering comparison: once using the transformed template-1 as the argument template and template-2 as the parameter template and again using the transformed template-2 as the argument template and template-1 as the parameter template.

  2. The types used to determine the ordering depend on the context in which the partial ordering is done:

    1. In the context of a function call, the types used are those function parameter types for which the function call has arguments.

...

  1. Function template F is at least as specialized as function template G if, for each pair of types used to determine the ordering, the type from F is at least as specialized as the type from G. F is more specialized than G if F is at least as specialized as G and G is not at least as specialized as F.

因此,我们需要模板的部分作为函数参数。

a) T                 =>  std::ostream&,                     T const&
b) CharT, Traits     =>  std::basic_ostream<CharT, Traits>, const char*
c) T, CharT, Traits  =>  std::basic_ostream<CharT, Traits>, T const&

对于这些函数的第一个参数,abc 更专业。

对于这些函数的第二个参数,bac 更专业。

正如我们在 [temp.deduct.partial]/10 中学到的,参数推导要求函数 f1 的所有相关参数至少与函数 f2 的所有参数一样专业对于函数f1至少与f2一样特化,a在这里不能比b<更特化/em>,因为每个参数都有一个比另一个匹配参数更专业的参数。

c 的情况并非如此,因为 ac 的所有参数至少与 < 中的参数一样专业em>c.

因此,重载解析在选择 ab 时会变得不明确,因为 a 至少与 bb 至少与 a 一样专业。通过使用 c 而不是 a 可以消除歧义,因为 b 至少与 c 一样特化,但是反过来则不然。

正如我们从 [temp.func.order]/2 中了解到的,更专业的函数会赢得重载解析,并且使用 c 而不是 a,获胜者是 b,行 std::cout << "hello";打印hello到控制台。

关于c++ - 为什么运算符 << 不明确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42957146/

相关文章:

c++ - 自己的智能指针的模板特化

c++ - 在文本文件的特定行和列上插入值

c++ - otool 输出中的相对路径?

scala - 为什么 Scala 类型推断在这里失败?

c++ - 使用经典重载解析规则创建依赖于 std::invoke 的重载集类

c++ - 为什么 auto 不能用于重载函数?

可以抛出和不能抛出的方法中的 Swift 类型推断

c++ - Exiftool 获取图像信息

c++ - synergy 无法编译——对 `pthread_xxxx 的 undefined reference

java - 可以自动重载吗?