【问题标题】:C++ operator<< compile error with gtest AssertionFailureC++ 运算符<< 使用 gtest AssertionFailure 编译错误
【发布时间】:2016-06-23 05:32:47
【问题描述】:

更新:我已经简化了这个问题的代码,并删除了原始的更复杂的代码。

请帮助我了解导致我在下面描述的错误的原因。

我已经定义了一个简单的 4xfloat 向量类型Vector4f。现在我只定义了索引运算符,但最终我将定义加法、减法等运算符。我还定义了一个流运算符,用于将向量序列化为流。此运算符仅使用公共方法,因此它不是Vector4ffriend

矢量.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 (clang) 进行编译。流序列化模板似乎适用于 ostream:

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

我遇到问题的地方是 GoogleTest 的 AssertionFailure 类,它可以与流运算符一起使用来添加信息。我希望最终使用辅助函数来检查向量是否包含我期望的值(不依赖于尚不存在的相等运算符)。为简单起见,我在这里直接使用断言:

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

据我了解,将 Vector 类的 operator&lt;&lt; 模板的结果应用于 testing::AssertionFailure 类的 operator&lt;&lt; 时遇到问题。我不明白为什么这会导致问题,因为它应该在将我的向量序列化为字符串流之后调用 AssertionFailure 的运算符。这里发生了一些我还不明白的事情,我当然也不明白错误消息本身。

任何帮助,请。

【问题讨论】:

  • 这对我来说信息太多了。请发帖Minimal, Complete, and Verifiable example
  • @RSahu 好的,谢谢您的建议。我已经用一个显示相同编译器错误的更简单版本更新了我的问题。
  • 我不明白为什么你的operator&lt;&lt; 函数必须是一个模板并且不能只使用std::ostream 类。这可能会一直解决问题。
  • 看来应该可以了。也许比我更有知识的人可以帮助你。
  • @AntonioPérez 如果我将StreamType 替换为::std::ostream(并将其从模板中删除,并合并@nm 的修复程序),我会收到错误:invalid operands to binary expression for @987654337 @ 和 const char *s &lt;&lt; "[ " 位上。我不明白为什么这个简单的替换不起作用,但也许这是一个单独的问题的材料。

标签: c++ templates c++11 googletest crtp


【解决方案1】:
return s << "[ " << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << " ]";

应该是

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

这是因为operator&lt;&lt;(float)std::basic_ostream成员函数。它返回std::basic_ostream&lt;...&gt;&amp;,而不是您调用它的流的类型。您不能将其转换为StreamType&amp;,除非StreamType 恰好是basic_ostreamstd::cout 就是这种情况。

或者,将您的 operator&lt;&lt; 声明为

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

【讨论】:

  • 谢谢 - 第一个建议为我解决了这个问题,但我也会阅读可变参数模板参数,以便理解您的第二个建议。
  • 您知道为什么用std::ostream 替换StreamType 会导致我在问题的一个cmets 中提到的编译器错误吗?根据您的解释,我预计这会起作用,因为 std::ostreambasic_ostream&lt;char&gt;
  • @meowsqueak 我无法重现该错误。您可能在其他地方弄错了。但不推荐这种解决方案。如果有人使用std::wostream,或者使用非默认分配器,或者其他什么?
  • 这是我最初的想法 - 保持模板化,然后只要 StreamType 定义了 operator&lt;&lt;,它就应该可以工作。我很高兴保持原样。
猜你喜欢
  • 2012-08-13
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 2013-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多