大多数IO stream manipulators是具有以下签名的常规函数:
std::ios_base& func( std::ios_base& str );
然而,一些操纵者(包括最常用的操纵者 - std::endl
和std::flush
)是以下形式的模板:
template< class CharT, class Traits >
std::basic_ostream<CharT, Traits>& func(std::basic_ostream<CharT, Traits>& os);
然后,鉴于以下示例失败,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;
^
很明显,上下文(在std::cout << std::endl;
中)有助于编译器消除对std::endl
的引用的歧义。但是,管理该程序的规则是什么?对于重载分辨率来说,这似乎是一个真正的挑战,它必须同时回答两个问题:
std::endl<CharT, Traits>()
std::endl
的哪个专业化指的是什么?operator<<
指的是哪个功能?模板参数推导(1)应该在重载决策(2)之前发生,但似乎(至少某些部分)(2)需要执行才能使(1)成功。
有些相关但无法重复的问题是:
这些问题都没有,也没有对它们的回答都解决了模板参数推断的工作原理,它应该在重载决策之前,但必须得到后者的帮助。
后续问题: How does overload resolution work when an argument is an overloaded function?
答案 0 :(得分: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>&));
// ...
};
}
由于呼叫是std::cout << std::endl
,或等效std::cout.operator<<(std::endl)
,我们已经知道basic_ostream
:std::basic_ostream<char, std::char_traits<char>>
的确切实例,即std::ostream
。所以cout
的成员函数看起来像
std::ostream& operator<<(std::basic_ostream<char, std::char_traits<char>>& (*pf)
(std::basic_ostream<char, std::char_traits<char>>&));
此成员函数不是函数模板,只是普通的成员函数。那么剩下的问题是,它可以用名称std::endl
作为参数来调用吗?是的,初始化函数参数等同于变量初始化,就像我们编写了
std::basic_ostream<char, std::char_traits<char>>& (*pf)
(std::basic_ostream<char, std::char_traits<char>>&) = std::endl;
答案 1 :(得分:5)
因为basic_ostream
具有operator<<
的模板化重载,它只需要这样的函数指针:
basic_ostream<charT, traits>& operator<<(basic_ios<charT, traits>& (*pf)(basic_ios<charT, traits>&));
答案 2 :(得分:4)
给出表单
的语句表达式 std::cout << std::endl;
编译器有关于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>&));
};
由于编译器有关于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;
是因为std::endl
是模板化函数,并且此声明不提供专门化该模板的信息(即选择charT
或traits
是什么)。如果它无法专门化模板std::endl
,则无法推断该函数的返回类型,因此类型推导失败。
答案 3 :(得分:-3)
你需要把&lt;&lt;在结束之前。它是ofstream的成员:
$url = 'https://query.yahooapis.com/v1/public/yql?q=%20select%20*%20from%20weather.forecast%20where%20woeid%20in%20(SELECT%20woeid%20FROM%20geo.places%20WHERE%20text=%22(28.56,77.32)%22)%20and%20u=%27c%27&format=json';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
$output = curl_exec($ch);
endl就像&#34; / n&#34;跳过该行,所以你需要一个cout行跳过