有这段代码:
#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;
}
有两个错误:
/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;
它抱怨类型operator<<
和std::basic_ostream<char>
没有定义const std::vector<unsigned char>
,虽然它似乎已定义。我尝试了一些重载,但没有一个工作。如何正确地编译这段代码?
在g ++ 6.3上编译:
g++ main.cpp -lgmock -o main -L ./googletest-release-1.8.0/googlemock -pthread
答案 0 :(得分:2)
boost::operator<<(std::ostream&, boost::variant const&)
在boost/variant/detail/io.hpp
中定义,不幸的是推迟到找到ADL operator<<
。
如上所述,std命名空间中没有声明operator<<(std::ostream&, std::vector<> const&)
,声明一个是非法的。
解决方法是将此运算符注入boost::detail::variant
命名空间。
您不希望在生产代码中执行此操作,因为它依赖于boost的内部知识,但在测试中它可能是可接受的。
这个编译:
#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;
}
答案 1 :(得分:1)
前两个打印机功能没有用,因为变体不能转换为具有其类型子集的变体。其他的不起作用,因为编译器找不到它。 ADL仅查看定义类型的命名空间(在本例中为std
)。所以这个解决方案可行:
namespace std {
ostream& operator<<(
ostream& stream,
const vector<unsigned char>&)
{ return stream; }
ostream& operator<<(
ostream& stream,
const vector<int>&)
{ return stream; }
}
然而,这不是一个好主意。通常,您不应将任何内容放入std
命名空间。现在你真的需要它,但是设置一个过载的operator<<
有点过于干扰。好的是gtest为它提供了一种更好的方法,而是创建一个PrintTo()
函数:https://github.com/google/googletest/blob/master/googletest/docs/advanced.md#teaching-googletest-how-to-print-your-values。这样,您必须为整个变体创建一个打印机,这意味着您必须创建一个执行实际打印的访问者。
class Printer : public boost::static_visitor<void> {
public:
Printer(std::ostream& stream) : stream(stream) {}
void operator()(const std::vector<unsigned char>&) const {}
void operator()(const std::vector<int>&) const {}
private:
std::ostream& stream;
};
namespace boost {
void PrintTo(const CustomVariant& v, std::ostream* stream) {
boost::apply_visitor(Printer(*stream), v);
}
}
如果单个元素的打印类似,您还可以在访问者中使用模板功能:
class Printer : public boost::static_visitor<void> {
public:
Printer(std::ostream& stream) : stream(stream) {}
template<typename T>
void operator()(const std::vector<T>& v) const {
for (const T& t : v) {
// do something
}
}
private:
std::ostream& stream;
};