使用std :: vector <boost :: variant <...>&gt;使用Google Mock会导致编译错误

时间:2017-09-21 11:46:34

标签: c++ c++11 gmock boost-variant

有这段代码:

#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

2 个答案:

答案 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;
};