2016-06-23 21 views
0

UPDATE: Ich habe diesen Code der Frage vereinfacht, und entfernte den ursprünglichen, komplexeren Code.C++ - Operator << kompilieren Fehler mit gtest AssertionFailure

Bitte helfen Sie mir zu verstehen, was den Fehler verursacht, den ich unten beschreibe.

Ich habe einen einfachen 4xfloat Vektor Typ Vector4f definiert. Vorläufig habe ich nur den Indexoperator definiert, aber irgendwann werde ich Operatoren für Addition, Subtraktion usw. definieren. Ich habe auch einen Stream-Operator für die Serialisierung des Vektors in einen Stream definiert. Nur öffentliche Methoden werden von diesem Operator verwendet, daher ist es kein friend von Vector4f.

vector.h:

#ifndef VECTOR_HPP 
#define VECTOR_HPP 

namespace vector { 

class Vector4f { 
public: 
    Vector4f(float x0, float x1, float x2, float x3) : 
    storage_({x0, x1, x2, x3}) {} 

    float & operator[](size_t i) { return storage_[i]; } 
    const float & operator[](size_t i) const { return storage_[i]; } 

protected: 
    typedef std::vector<float> StorageType; 
    StorageType storage_; 
}; 

template <typename StreamType> 
StreamType & operator<<(StreamType & s, const Vector4f & v) { 
    return s << "[ " << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << " ]"; 
} 

} // namespace vector 

#endif // VECTOR_HPP 

Ich Kompilieren mit C++ 11 (Klappern). Der Strom Serialisierung Vorlage scheint für Ostream zu arbeiten:

std::cout << vector::Vector4f(1,2,3,4) << std::endl; // compiles 

Wo ich Probleme mit GoogleTest der AssertionFailure Klasse ist, die mit einem Strom Operator verwendet werden kann, Informationen hinzuzufügen. Ich versuche, eine Hilfsfunktion zu verwenden, um zu überprüfen, dass ein Vektor die Werte enthält, die ich erwarte (ohne auf einen Gleichheitsoperator zu vertrauen, der noch nicht vorhanden ist). Der Einfachheit halber verwende ich die Behauptung direkt hier:

test_vector.cc:

#include <gtest/gtest.h> 
#include "vector.h" 

class TestVector : public ::testing::Test {}; 

TEST_F(TestVector, ctor_by_float_parameters) { 
    vector::Vector4f v(0.0f, 0.1f, 0.2f, 0.3f); 
    EXPECT_TRUE(::testing::AssertionFailure() << v); 
} 

Der Compiler mit diesem Fehler fehlschlägt:

In file included from test_vector2.cc:2: 
./vector2.h:21:10: error: non-const lvalue reference to type 'std::__1::basic_stringstream<char, 
     std::__1::char_traits<char>, std::__1::allocator<char> >' cannot bind to a value of unrelated type 
     'basic_ostream<char, std::__1::char_traits<char> >' 
    return s << "[ " << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << " ]"; 
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
googletest/include/gtest/gtest-message.h:131:10: note: in instantiation of function template specialization 
     'vector::operator<<<std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> > >' 
     requested here 
    *ss_ << val; 
     ^
googletest/include/gtest/gtest.h:306:29: note: in instantiation of function template specialization 
     'testing::Message::operator<<<vector::Vector4f>' requested here 
    AppendMessage(Message() << value); 
          ^
test_vector2.cc:10:45: note: in instantiation of function template specialization 
     'testing::AssertionResult::operator<<<vector::Vector4f>' requested here 
    EXPECT_TRUE(::testing::AssertionFailure() << v); 

Von dem, was ich verstehe, ist es mit Schwierigkeiten Anwenden des Ergebnisses der Vorlage operator<< für meine Vector-Klasse auf die operator<< für die Klasse testing :: AssertionFailure. Ich verstehe nicht, warum dies ein Problem verursacht, da es den Operator von AssertionFailure aufrufen sollte, nachdem es meinen Vektor in einen Stringstream serialisiert hat. Hier passiert etwas, was ich noch nicht verstehe, und ich verstehe die Fehlermeldung selbst nicht.

Jede Hilfe, bitte, bitte.

+2

Das ist für mich zu viel Information. Bitte veröffentlichen Sie ein [minimales, vollständiges und überprüfbares Beispiel] (http://stackoverflow.com/help/mcve). –

+0

@RSahu ok, danke für deinen Rat. Ich habe meine Frage mit einer einfacheren Version aktualisiert, die denselben Compilerfehler aufweist. – meowsqueak

+1

Ich verstehe nicht, warum Ihre 'operator <<' Funktion eine Vorlage sein muss und nicht einfach die Klasse 'std :: ostream' verwenden kann.Das würde wahrscheinlich das Problem die ganze Zeit beseitigen. –

Antwort

2
return s << "[ " << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << " ]"; 

sollte

s << "[ " << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << " ]"; 
return s; 

Dies liegt daran, dass sein operator<<(float) eine Funktion von std::basic_ostreamMitglied ist. Es gibt std::basic_ostream<...>& zurück, nicht den Typ des Streams, mit dem Sie es aufrufen. Sie können es nicht in StreamType& konvertieren, es sei denn, StreamType ist zufällig ein basic_ostream, was der Fall mit std::cout ist.

Alternativ erklären Ihre operator<< als

template <typename VectorType, typename... StreamArgs> 
std::basic_ostream<StreamArgs...> & 
operator << (std::basic_ostream<StreamArgs...>& s, 
       const BaseVector<VectorType> & v) 
+0

Danke - der erste Vorschlag hat das Problem für mich gelöst, aber ich werde auch auf Variadic Template Argumente nachlesen, damit ich Ihren zweiten Vorschlag verstehen kann. – meowsqueak

+0

Wissen Sie, warum das Ersetzen von "StreamType" durch "std :: ostream" den Compilerfehler verursacht, den ich in einem der Kommentare zu meiner Frage erwähnt habe? Basierend auf dem, was Sie erklärt haben, hätte ich erwartet, dass dies funktioniert, da "std :: ostream" ein 'basic_ostream '' ist. – meowsqueak

+0

@meowsqueak Ich konnte diesen Fehler nicht reproduzieren. Du hast es wahrscheinlich woanders falsch gemacht. Aber diese Lösung wird nicht empfohlen. Was passiert, wenn jemand 'std :: wostream' verwendet oder einen mit einem nicht standardmäßigen Allokator oder was auch immer? –