我怎样才能允许将向量传递给 INFO()、CAPTURE()、WARN() 等,同时避免非法扩展 std 名称空间?
How can I allow vector to be passed to INFO(), CAPTURE(), WARN(), etc. while avoiding illegally extending the std namespace?
在 Catch Unit Test v1.8.1 中,使用 gcc 6.2.0,我试图在测试失败时通过将向量传递给 INFO(...)
或 [=15= 来方便地输出向量的内容].为此,我重载了流插入运算符:
#include <Catch/single_include/catch.hpp>
#include <vector>
#include <iostream>
#define THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
#ifdef THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
namespace std {
#endif
std::ostream& operator<<( std::ostream& os, const std::vector<int>& v ) {
for ( const auto& e : v ) {
os << e << " ";
}
return os;
}
#ifdef THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
} //namespace std
#endif
int some_operation_on_vector( const std::vector<int>& v ) {
return 1;
}
SCENARIO( "some scenario" )
{
GIVEN( "a vector" )
{
const auto the_vector = std::vector<int>{ 1, 2, 3, 4, 5 };
WHEN( "some result is calculated from the vector" )
{
const auto actual_result = some_operation_on_vector( the_vector );
THEN( "the result should be correct. If not, print out the vector." )
{
const auto expected_result = 0;
CAPTURE( the_vector ); // <--------
//^^^^
//How do I legally make this work?
REQUIRE( expected_result == actual_result );
}
}
}
}
如果我(非法)像上面那样扩展 std
命名空间,那么它就可以工作,并且我看到了所需的输出:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
catchtestexample is a Catch v1.8.1 host application.
Run with -? for options
-------------------------------------------------------------------------------
Scenario: some scenario
Given: a vector
When: some result is calculated from the vector
Then: the result should be correct. If not, print out the vector.
-------------------------------------------------------------------------------
ExampleTest.cpp:91
...............................................................................
ExampleTest.cpp:95: FAILED:
REQUIRE( expected_result == actual_result )
with expansion:
0 == 1
with message:
the_vector := 1 2 3 4 5
===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed
但是为了合法,当我尝试将 operator<<
重载移出 std
命名空间并移入全局命名空间(通过注释掉 #define THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
)时,由于将向量传递给 CAPTURE()
宏,代码无法编译。
根据 Catch docs,我尝试用 Catch::toString
重载替换 operator <<
重载:
#include <string>
#include <sstream>
namespace Catch {
std::string toString( const std::vector<int>& v ) {
std::ostringstream ss;
for ( const auto& e : v ) {
ss << e << " ";
}
return ss.str();
}
}
或 Catch::StringMaker
专长:
#include <string>
#include <sstream>
namespace Catch {
template<> struct StringMaker<std::vector<int>> {
static std::string convert( const std::vector<int>& v ) {
std::ostringstream ss;
for ( const auto& e : v ) {
ss << e << " ";
}
return ss.str();
}
};
}
但在任何一种情况下,由于将向量传递给 CAPTURE()
宏,测试仍然无法编译。
Catch 文档说将 operator<<
重载放入与您的类型相同的命名空间,但 std::vector
不是我的类型,并且将该重载放入命名空间 std
是非法的.
但我找到的唯一方法是让 CAPTURE()
(或 INFO()
、或 WARN()
等)接受 std::vector
参数是非法将 operator<<
重载放入命名空间 std
.
是否有适当、合法的方法来做到这一点?
我想我找到了有效的答案。 (编辑:请参阅 以获得更好的解决方案。)
不是将 operator<<
重载放入 std
命名空间,而是将其放入 Catch
命名空间编译并给出所需的行为:
namespace Catch {
std::ostream& operator<<( std::ostream& os, const std::vector<int>& v ) {
for ( const auto& e : v ) {
os << e << " ";
}
return os;
}
}
Catch docs 说要将 operator<<
重载放入与您的类型相同的名称空间中:
operator<< overload for std::ostream
This is the standard way of providing string conversions in C++ - and the chances are you may already provide this for your own purposes. If you're not familiar with this idiom it involves writing a free function of the form:
std::ostream& operator<<( std::ostream& os, T const& value ) {
os << convertMyTypeToString( value );
return os;
}
(where T
is your type and convertMyTypeToString
is where you'll write whatever code is necessary to make your type printable - it doesn't have to be in another function).
You should put this function in the same namespace as your type. [Emphasis mine]
Alternatively you may prefer to write it as a member function:
std::ostream& T::operator<<( std::ostream& os ) const {
os << convertMyTypeToString( *this );
return os;
}
但是由于 std::vector 不是 my 类型,并且它存在于命名空间 std
中,所以我无法按照文档所说的去做.
那么可以将 operator<<
重载放入 Catch
命名空间吗?它有效,但是可以吗?如果我这样做会发生坏事吗?文档确实说可以将 toString
的重载放入 Catch 命名空间,那么 operator<<
重载也可以吗?
我想我找到了一些比 更好的解决方案:
解决方案 1:
将 Catch 更新到 v1.8.2 或更高版本。从一些快速测试来看,v1.8.2 似乎在 CAPTURE 宏中添加了对 std::vector
的支持,您无需付出任何额外的努力。在这种情况下,不需要为 std::vector
重载 operator<<
。
解决方案 2:
如果您出于某种原因无法更新到 Catch v1.8.2 或更新版本,此解决方案类似于我在原始问题中提出的解决方案,但基于 C++ 委员会成员 Jonathan 的 进行了改进Wakely(谢谢!)。
他给出了以下建议:
Don't overload operators for types you don't control.
...
Instead create a tiny adaptor class and define the operator for that...
考虑到这一点:
#include <Catch/single_include/catch.hpp>
#include <vector>
#include <iostream>
template <typename T> struct PrintableVector {
const std::vector<T>& vec;
};
template <typename T>
PrintableVector<T> makePrintable( const std::vector<T>& vec ) {
return PrintableVector<T>{ vec };
}
template <typename T>
std::ostream& operator<<( std::ostream& os, const PrintableVector<T>& printableVec ) {
for ( const auto& e : printableVec.vec ) {
os << e << " ";
}
return os;
}
int some_operation_on_vector( const std::vector<int>& v ) {
return 1;
}
SCENARIO( "some scenario" )
{
GIVEN( "a vector" )
{
const auto the_vector = std::vector<int>{ 1, 2, 3, 4, 5 };
WHEN( "some result is calculated from the vector" )
{
const auto actual_result = some_operation_on_vector( the_vector );
THEN( "the result should be correct. If not, print out the vector." )
{
const auto expected_result = 0;
CAPTURE( makePrintable( the_vector ) );
REQUIRE( expected_result == actual_result );
}
}
}
}
这在 Catch v1.8.1 上编译和运行,并给出以下输出:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
catchtestexample is a Catch v1.8.1 host application.
Run with -? for options
-------------------------------------------------------------------------------
Scenario: some scenario
Given: a vector
When: some result is calculated from the vector
Then: the result should be correct. If not, print out the vector.
-------------------------------------------------------------------------------
main.cpp:43
...............................................................................
main.cpp:47: FAILED:
REQUIRE( expected_result == actual_result )
with expansion:
0 == 1
with message:
makePrintable( the_vector ) := 1 2 3 4 5
===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed
在 Catch Unit Test v1.8.1 中,使用 gcc 6.2.0,我试图在测试失败时通过将向量传递给 INFO(...)
或 [=15= 来方便地输出向量的内容].为此,我重载了流插入运算符:
#include <Catch/single_include/catch.hpp>
#include <vector>
#include <iostream>
#define THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
#ifdef THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
namespace std {
#endif
std::ostream& operator<<( std::ostream& os, const std::vector<int>& v ) {
for ( const auto& e : v ) {
os << e << " ";
}
return os;
}
#ifdef THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
} //namespace std
#endif
int some_operation_on_vector( const std::vector<int>& v ) {
return 1;
}
SCENARIO( "some scenario" )
{
GIVEN( "a vector" )
{
const auto the_vector = std::vector<int>{ 1, 2, 3, 4, 5 };
WHEN( "some result is calculated from the vector" )
{
const auto actual_result = some_operation_on_vector( the_vector );
THEN( "the result should be correct. If not, print out the vector." )
{
const auto expected_result = 0;
CAPTURE( the_vector ); // <--------
//^^^^
//How do I legally make this work?
REQUIRE( expected_result == actual_result );
}
}
}
}
如果我(非法)像上面那样扩展 std
命名空间,那么它就可以工作,并且我看到了所需的输出:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
catchtestexample is a Catch v1.8.1 host application.
Run with -? for options
-------------------------------------------------------------------------------
Scenario: some scenario
Given: a vector
When: some result is calculated from the vector
Then: the result should be correct. If not, print out the vector.
-------------------------------------------------------------------------------
ExampleTest.cpp:91
...............................................................................
ExampleTest.cpp:95: FAILED:
REQUIRE( expected_result == actual_result )
with expansion:
0 == 1
with message:
the_vector := 1 2 3 4 5
===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed
但是为了合法,当我尝试将 operator<<
重载移出 std
命名空间并移入全局命名空间(通过注释掉 #define THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
)时,由于将向量传递给 CAPTURE()
宏,代码无法编译。
根据 Catch docs,我尝试用 Catch::toString
重载替换 operator <<
重载:
#include <string>
#include <sstream>
namespace Catch {
std::string toString( const std::vector<int>& v ) {
std::ostringstream ss;
for ( const auto& e : v ) {
ss << e << " ";
}
return ss.str();
}
}
或 Catch::StringMaker
专长:
#include <string>
#include <sstream>
namespace Catch {
template<> struct StringMaker<std::vector<int>> {
static std::string convert( const std::vector<int>& v ) {
std::ostringstream ss;
for ( const auto& e : v ) {
ss << e << " ";
}
return ss.str();
}
};
}
但在任何一种情况下,由于将向量传递给 CAPTURE()
宏,测试仍然无法编译。
Catch 文档说将 operator<<
重载放入与您的类型相同的命名空间,但 std::vector
不是我的类型,并且将该重载放入命名空间 std
是非法的.
但我找到的唯一方法是让 CAPTURE()
(或 INFO()
、或 WARN()
等)接受 std::vector
参数是非法将 operator<<
重载放入命名空间 std
.
是否有适当、合法的方法来做到这一点?
我想我找到了有效的答案。 (编辑:请参阅
不是将 operator<<
重载放入 std
命名空间,而是将其放入 Catch
命名空间编译并给出所需的行为:
namespace Catch {
std::ostream& operator<<( std::ostream& os, const std::vector<int>& v ) {
for ( const auto& e : v ) {
os << e << " ";
}
return os;
}
}
Catch docs 说要将 operator<<
重载放入与您的类型相同的名称空间中:
operator<< overload for std::ostream
This is the standard way of providing string conversions in C++ - and the chances are you may already provide this for your own purposes. If you're not familiar with this idiom it involves writing a free function of the form:
std::ostream& operator<<( std::ostream& os, T const& value ) { os << convertMyTypeToString( value ); return os; }
(where
T
is your type andconvertMyTypeToString
is where you'll write whatever code is necessary to make your type printable - it doesn't have to be in another function).You should put this function in the same namespace as your type. [Emphasis mine]
Alternatively you may prefer to write it as a member function:
std::ostream& T::operator<<( std::ostream& os ) const { os << convertMyTypeToString( *this ); return os; }
但是由于 std::vector 不是 my 类型,并且它存在于命名空间 std
中,所以我无法按照文档所说的去做.
那么可以将 operator<<
重载放入 Catch
命名空间吗?它有效,但是可以吗?如果我这样做会发生坏事吗?文档确实说可以将 toString
的重载放入 Catch 命名空间,那么 operator<<
重载也可以吗?
我想我找到了一些比
解决方案 1:
将 Catch 更新到 v1.8.2 或更高版本。从一些快速测试来看,v1.8.2 似乎在 CAPTURE 宏中添加了对 std::vector
的支持,您无需付出任何额外的努力。在这种情况下,不需要为 std::vector
重载 operator<<
。
解决方案 2:
如果您出于某种原因无法更新到 Catch v1.8.2 或更新版本,此解决方案类似于我在原始问题中提出的解决方案,但基于 C++ 委员会成员 Jonathan 的
他给出了以下建议:
Don't overload operators for types you don't control.
...
Instead create a tiny adaptor class and define the operator for that...
考虑到这一点:
#include <Catch/single_include/catch.hpp>
#include <vector>
#include <iostream>
template <typename T> struct PrintableVector {
const std::vector<T>& vec;
};
template <typename T>
PrintableVector<T> makePrintable( const std::vector<T>& vec ) {
return PrintableVector<T>{ vec };
}
template <typename T>
std::ostream& operator<<( std::ostream& os, const PrintableVector<T>& printableVec ) {
for ( const auto& e : printableVec.vec ) {
os << e << " ";
}
return os;
}
int some_operation_on_vector( const std::vector<int>& v ) {
return 1;
}
SCENARIO( "some scenario" )
{
GIVEN( "a vector" )
{
const auto the_vector = std::vector<int>{ 1, 2, 3, 4, 5 };
WHEN( "some result is calculated from the vector" )
{
const auto actual_result = some_operation_on_vector( the_vector );
THEN( "the result should be correct. If not, print out the vector." )
{
const auto expected_result = 0;
CAPTURE( makePrintable( the_vector ) );
REQUIRE( expected_result == actual_result );
}
}
}
}
这在 Catch v1.8.1 上编译和运行,并给出以下输出:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
catchtestexample is a Catch v1.8.1 host application.
Run with -? for options
-------------------------------------------------------------------------------
Scenario: some scenario
Given: a vector
When: some result is calculated from the vector
Then: the result should be correct. If not, print out the vector.
-------------------------------------------------------------------------------
main.cpp:43
...............................................................................
main.cpp:47: FAILED:
REQUIRE( expected_result == actual_result )
with expansion:
0 == 1
with message:
makePrintable( the_vector ) := 1 2 3 4 5
===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed