我正在移植一段代码,该代码是为Linux编写的,并使用gcc v4.8.2(使用-std = c ++ 11)编译到Windows。部分原因是MSVC ++ 2013不同意的重载operator<<
。下面是一个简洁的例子。
我们定义了一个支持标准流操纵器功能的自定义流类。出于这个原因,我们重载operator<<
,它接受一个函数指针作为第二个参数。
如果我定义了运算符的模板化重载&lt;&lt;为... MSVC ++抱怨:
错误C2676:二进制'&lt;&lt;' :'foobar'没有定义此运算符 或转换为预定义运算符可接受的类型
但是,如果我将第二个参数的类型指定为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;
}
答案 0 :(得分:1)
默认参数,重载运算符和模板函数参数重载解析似乎存在某种错误。
这些都很复杂,所以可以理解。
好消息是你不应该只在那里任何 iomanip - 你应该选择一个特定的。
您可以对其进行硬编码,也可以按如此推断:
// Get the nth type from a template instance:
template<class...>struct types{using type=types;};
template<class T, size_t N>
struct nth{};
template<class T, size_t N>
using nth_t=typename nth<T,N>::type;
template<template<class...>class Z, class T0, class...Ts, size_t N>
struct nth<Z<T0,Ts...>,N>:nth<types<Ts...>,N-1>{};
template<template<class...>class Z, class T0, class...Ts>
struct nth<Z<T0,Ts...>,0>{using type=T0;};
// From a String type, produce a compatible basic_stream type:
template<class String>
using compat_stream = std::basic_ostream<nth_t<String,0>, nth_t<String,1>>;
// From a type T, produce a signature of a function pointer that
// pass-through manipulates it:
template<class T>
using manip_f = T&(*)(T&);
// From a String type, produce a compatible io-manipulator:
template<class String>
using io_manip_f = manip_f< compat_stream<String> >;
// The return of foobar:
struct foobar {
std::stringstream s_;
// the type of manipulators that is compatible with s_:
using manip_f = io_manip_f<std::stringstream> manip;
// a Koenig operator<<:
friend foobar& operator<<( foobar& self, manip_f manip ) {
self.s_ << manip;
return self;
}
};