Leo*_*eon 15 c++ templates overload-resolution iomanip
大多数IO流操纵器都是具有以下签名的常规函数:
std::ios_base& func( std::ios_base& str );
Run Code Online (Sandbox Code Playgroud)
但是,一些操纵器(包括最常用的操纵器 - std::endl和std::flush)是以下形式的模板:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& func(std::basic_ostream<CharT, Traits>& os);
Run Code Online (Sandbox Code Playgroud)
然后,如果std::cout << std::endl;以下示例失败,如何编译成功:
$ cat main.cpp
#include <iostream>
int main()
{
auto myendl = std::endl;
std::cout << myendl;
}
$ g++ -std=c++11 main.cpp -o main
main.cpp: In function ‘int main()’:
main.cpp:5:24: error: unable to deduce ‘auto’ from ‘std::endl’
auto myendl = std::endl;
^
Run Code Online (Sandbox Code Playgroud)
很明显,上下文(in std::cout << std::endl;)有助于编译器消除对引用的歧义std::endl.但是,管理该程序的规则是什么?对于重载分辨率来说,这似乎是一个真正的挑战,它必须同时回答两个问题:
std::endl<CharT, Traits>()确实std::endl参考?operator<<参考哪个功能?模板参数推导(1)应该在重载决策(2)之前发生,但似乎(至少某些部分)(2)需要执行以便(1)成功.
有些相关但无法重复的问题是:
这些问题都没有,也没有对它们的回答都解决了模板参数推断的工作原理,它应该在重载解决之前,但必须得到后者的帮助.
后续问题: 当参数是一个重载函数时,重载解析如何工作?
asc*_*ler 10
该operator<<问题是一个成员的std::basic_ostream:
namespace std {
template <class charT, class traits = char_traits<charT> >
class basic_ostream {
public:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
// ...
};
}
Run Code Online (Sandbox Code Playgroud)
由于调用是std::cout << std::endl或等效地std::cout.operator<<(std::endl),我们已经知道确切的实例化basic_ostream:std::basic_ostream<char, std::char_traits<char>>,aka std::ostream.所以成员函数cout看起来像
std::ostream& operator<<(std::basic_ostream<char, std::char_traits<char>>& (*pf)
(std::basic_ostream<char, std::char_traits<char>>&));
Run Code Online (Sandbox Code Playgroud)
该成员函数不是函数模板,只是普通的成员函数.所以剩下的问题是,它可以用名称std::endl作为参数来调用吗?是的,初始化函数参数等同于变量初始化,就像我们编写的那样
std::basic_ostream<char, std::char_traits<char>>& (*pf)
(std::basic_ostream<char, std::char_traits<char>>&) = std::endl;
Run Code Online (Sandbox Code Playgroud)
因为basic_ostream有一个模板化的重载operator<<,只需要这样一个函数指针:
basic_ostream<charT, traits>& operator<<(basic_ios<charT, traits>& (*pf)(basic_ios<charT, traits>&));
Run Code Online (Sandbox Code Playgroud)
给定形式的语句表达式
std::cout << std::endl;
Run Code Online (Sandbox Code Playgroud)
编译器有关于类型的信息std::cout- 这是模板的特化std::basic_ostream,看起来像(省略包含namespace std)。
template <class charT, class traits = char_traits<charT> >
class basic_ostream
{
public:
basic_ostream<charT,traits>& operator<<(
basic_ostream<charT,traits>& (*pf)(basic_ostream<charT,traits>&));
// other members ....
};
Run Code Online (Sandbox Code Playgroud)
由于编译器有关的类型,std::cout它知道什么charT,并traits有专门的前述模板。
上述原因std::endl在表达式std::cout << std::endl中匹配到特定的std::basic_ostream<charT, traits>& endl( std::basic_ostream<charT, traits>&).
原因类型推导不起作用
auto myendl = std::endl;
Run Code Online (Sandbox Code Playgroud)
是因为std::endl是一个模板化的函数,并且这个声明没有提供信息来专门化那个模板(即选择什么charT或是什么traits)。如果它不能特化 templated std::endl,它就不能推断该函数的返回类型,因此类型推导失败。
| 归档时间: |
|
| 查看次数: |
1961 次 |
| 最近记录: |