【发布时间】:2015-05-29 14:00:07
【问题描述】:
我正在将一段为 Linux 编写并使用 gcc v4.8.2(使用 -std=c++11)编译的代码移植到 Windows。其中一部分是 MSVC++ 2013 不同意的重载 operator<<。下面是一个精简的例子。
我们已经定义了一个支持标准流操纵器功能的自定义流类。出于这个原因,我们重载了operator<<,它接受一个函数指针作为第二个参数。
如果我定义了 operator
错误 C2676:二进制“
但是,如果我将第二个参数的类型指定为 std::ostream 而不是模板化的 std::basis_ostream<..,..>,则代码将按预期工作。
起初我以为我搞砸了模板参数。但是,如果我定义一个任意模板函数而不是 operator<< 的重载,则代码编译得很好。这是怎么回事?
示例
#include "stdafx.h"
#include <iostream>
#include <sstream>
#include <string>
struct foobar {
std::stringstream s_;
};
/* Causes compiler error C2676
template <typename CharT = char, typename Traits = std::char_traits<CharT> >
foobar& operator<<(foobar& foo, std::basic_ostream<CharT, Traits>& (*manip)(std::basic_ostream<CharT, Traits>&))
{
foo.s_ << manip;
return foo;
}
*/
/* works as intendend */
foobar& operator<<(foobar& foo, std::ostream& (*manip)(std::ostream&))
{
foo.s_ << manip;
return foo;
}
/* works too */
template <typename CharT = char, typename Traits = std::char_traits<CharT> >
foobar& qux(foobar& foo, std::basic_ostream<CharT, Traits>& (*manip)(std::basic_ostream<CharT, Traits>&))
{
foo.s_ << manip;
return foo;
}
int _tmain(int argc, _TCHAR* argv[])
{
foobar foo;
foo << std::endl;
qux(foo, std::endl);
return 0;
}
【问题讨论】:
-
看起来像一个编译器错误。 g++5.1 和 clang++3.6 都接受程序,以及 vc++19(参见例如webcompiler.cloudapp.net)
-
std::endl不是函数,它是模板函数。你将它传递给一个特定的签名,它会发现过载。你将一个带有类型模板的函数传递给它,它搞砸了?但仅当您进行运算符重载时。 -
请注意,
CharT和Traits永远无法推导出来(因为std::endl是一个函数模板),因此您也可以使用您的第二个版本的operator<<。 -
真的,
<<的manip应该从stringstream推导出它的CharT和Traits不? -
@Yakk 怎么样?
decltype(foobar::s_)?
标签: c++11 visual-c++