2017-09-21 8 views
0

コンパイルエラーが発生し使用のstd ::ベクトル<ブースト::バリアント<...>>は、このコードがある

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

それは、と文句を言いますが定義されているように見えますが、タイプstd::basic_ostream<char>const std::vector<unsigned char>の場合はoperator<<と定義されていません。私はいくつかの過負荷を試みたが、どれも働いていなかった。このコードを正しくコンパイルするには?

グラム++ 6.3でコンパイル:

g++ main.cpp -lgmock -o main -L ./googletest-release-1.8.0/googlemock -pthread 

答えて

2

boost::operator<<(std::ostream&, boost::variant const&)boost/variant/detail/io.hppで定義されており、残念ながらADL-たoperator<<に延期されます。

前述のとおり、operator<<(std::ostream&, std::vector<> const&)はstd名前空間で宣言されておらず、宣言するのは不正です。

回避方法は、この演算子をboost::detail::variant名前空間に挿入することです。

ブーストの内部知識に依存しているため、プロダクションコードではこれを実行したくないかもしれませんが、テストでは問題ありません。

これはコンパイル:

#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

変異体は、そのタイプのサブセットを有する変異体に変換できないように最初の二つのプリンタ機能は、全く使用していません。コンパイラがそれを見つけることができないため、他の関数は動作しません。 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<<を置くことはややこしいことです。良いことは、代わりにPrintTo()関数を作成して、gtestがより良い方法を提供することです:https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#teaching-google-test-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; 
}; 
関連する問題