There is this code:
#include "gmock/gmock.h"
#include <boost/variant.hpp>
typedef boost::variant<std::vector<unsigned char>, std::vector<int>> CustomVariant;
// some overloads which don't work
std::ostream& operator<<(
std::ostream& stream,
const boost::variant<std::vector<unsigned char>>&)
{ return stream; }
std::ostream& operator<<(
std::ostream& stream,
const boost::variant<std::vector<int>>&)
{ return stream; }
std::ostream& operator<<(
std::ostream& stream,
const std::vector<unsigned char>&)
{ return stream; }
std::ostream& operator<<(
std::ostream& stream,
const std::vector<int>&)
{ return stream; }
class MyClass
{
MOCK_METHOD1(fun, bool(std::vector<CustomVariant> v));
};
int main()
{
MyClass a;
return 0;
}
There are two errors:
/usr/include/boost/variant/detail/variant_io.hpp:64:14: error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘const std::vector<unsigned char>’)
out_ << operand;
/usr/include/boost/variant/detail/variant_io.hpp:64:14: error: cannot bind ‘std::basic_ostream<char>’ lvalue to ‘std::basic_ostream<char>&&’
out_ << operand;
It complains that there is not defined operator<<
for types std::basic_ostream<char>
and const std::vector<unsigned char>
, although it seems that it's defined. I tried some overloads but none of them worked. How to properly make this code to compile?
Compiling on g++ 6.3:
g++ main.cpp -lgmock -o main -L ./googletest-release-1.8.0/googlemock -pthread
boost::operator<<(std::ostream&, boost::variant const&)
is defined in boost/variant/detail/io.hpp
and unfortunately defers to an ADL-found operator<<
.
As mentioned, there is no operator<<(std::ostream&, std::vector<> const&)
declared in the std namespace and it's illegal to declare one.
A workaround is to inject this operator into the boost::detail::variant
namespace.
You wouldn't want to do this in production code because it relies on knowledge of the internals of boost, but in a test it may be acceptable.
this compiles:
#include "gmock/gmock.h"
#include <vector>
struct emitter
{
emitter(std::ostream& os) : os(os) {};
template<class T> std::ostream& operator()(T const& v) const
{
return os << v;
}
std::ostream& operator()(char c)
{
if (std::isprint(c))
{
return os << '\'' + c + '\'';
}
else
{
auto oldstate = os.flags();
os << std::hex << "0x" << (int(c) & 0xff);
os.flags(oldstate);
return os;
}
}
template<class T, class A>
std::ostream &operator()(const std::vector<T, A> &v) const
{
const char* sep = " ";
os << "[";
for (auto&& x : v)
{
(*this)(x);
sep = ", ";
}
return os << " ]";
}
std::ostream& os;
};
namespace boost { namespace detail { namespace variant {
template<class T, class A>
std::ostream &operator<<(std::ostream &os, std::vector<T, A>const &var)
{
auto e = emitter(os);
return e(var);
}
}}}
#include <boost/variant.hpp>
#include <iomanip>
typedef boost::variant<std::vector<unsigned char>, std::vector<int>> CustomVariant;
class MyClass
{
MOCK_METHOD1(fun, bool(std::vector<CustomVariant>v));
};
int main()
{
MyClass a;
return 0;
}