MSVC++ 看不到重载运算符<<



我正在将一段为Linux编写并使用gcc v4.8.2(使用-std=c++11)编译的代码移植到Windows上。它的一部分是超载的operator<<, msvc++ 2013不同意。下面是一个简明的例子。

我们已经定义了一个自定义流类,它支持标准的流操纵符函数。因此,我们重载了operator<<,它接受一个函数指针作为第二个参数。

如果我定义了operator<<对。MSVC + +抱怨:

错误C2676:二进制'<<': '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;
}

在默认实参、重载操作符和模板函数形参重载解析方面似乎存在某种错误。

这些都很复杂,所以可以理解。

好消息是,你不应该取任意的,你应该取一个特定的

你可以硬编码它,或者像这样推导它:

// 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;
  }
};

最新更新