2016-06-23 4 views
0

UPDATE: Я упростил этот вопрос и удалил оригинальный, более сложный код.Оператор на C++ << скомпилировать ошибку с gtest AssertionFailure

Пожалуйста, помогите мне понять, что вызывает ошибку, описанную ниже.

Я определил простой вектор 4xfloat типа Vector4f. На данный момент я только определил оператор индекса, однако в конечном итоге я буду определять операторы для сложения, вычитания и т. Д. Я также определил оператор потока для сериализации вектора к потоку. Этот оператор использует только общедоступные методы, поэтому он не является friend от 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 

Я компиляции с C++ 11 (лязг). Шаблон потока сериализации, кажется, работает для ostream:

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

Где я сталкиваюсь проблем с AssertionFailure класса GoogleTest в, который может быть использован с оператором потока для добавления информации. Я ищу в конце концов использовать вспомогательную функцию, чтобы проверить, что вектор содержит ожидаемые значения (не полагаясь на оператор равенства, который еще не существует). Для простоты я использую утверждение прямо здесь:

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); 
} 

Компилятор терпит неудачу с этой ошибкой:

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

Из того, что я понимаю, что есть проблема, применение результата шаблона operator<< для моего класса Vector для operator<< для тестирования: класс AssertionFailure. Я не понимаю, почему это вызывает проблему, поскольку она должна вызывать оператор AssertionFailure после того, как он сериализовал мой вектор в поток строк. Здесь что-то происходит, я еще не понимаю, и я, конечно, не понимаю самого сообщения об ошибке.

Любая помощь приветствуется, пожалуйста.

+2

Это слишком много информации для меня. Пожалуйста, напишите [Минимальный, Полный и Подтверждаемый пример] (http://stackoverflow.com/help/mcve). –

+0

@RSahu хорошо, спасибо за ваш совет. Я обновил свой вопрос с более простой версией, которая демонстрирует ту же ошибку компилятора. – meowsqueak

+1

Я не понимаю, почему ваша функция 'operator <<' должна быть шаблоном и не может просто использовать класс' std :: ostream'.Вероятно, это устранит проблему. –

ответ

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

должно быть

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

Это потому, что operator<<(float) является функцией членом из std::basic_ostream. Он возвращает std::basic_ostream<...>&, а не тип потока, с которым вы его вызываете. Вы не можете преобразовать его в StreamType&, если StreamType не является basic_ostream, что в случае с std::cout.

В качестве альтернативы, объявить operator<<, как

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

Благодарим вас - первое предложение разрешило проблему для меня, однако я также буду читать вариационные аргументы шаблона, чтобы я мог понять ваше второе предложение. – meowsqueak

+0

Вы знаете, почему замена 'StreamType' на' std :: ostream' вызывает ошибку компилятора, упомянутую мной в одном из комментариев по моему вопросу? Основываясь на том, что вы объяснили, я бы ожидал, что это сработает, поскольку 'std :: ostream' является' basic_ostream '. – meowsqueak

+0

@meowsqueak Я не мог воспроизвести эту ошибку. Вероятно, это было неправильно. Но это решение не рекомендуется. Что делать, если кто-то использует 'std :: wostream', или тот, у кого нет распределителя по умолчанию, или что-то еще? –

 Смежные вопросы

  • Нет связанных вопросов^_^