-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CHECK and REQUIRE can't expand a custom type (QString) #531
Comments
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
struct QString {
std::string _;
const std::string & toStdString() const { return _; }
bool operator==(const QString & rhs) { return _ == rhs._; }
};
std::ostream& operator <<( std::ostream& os, QString const& value ) {
os << value.toStdString();
return os;
}
TEST_CASE("My testcase") {
CAPTURE(QString{"moo"});
INFO(QString{"Sauce"});
CHECK(QString{"moo"} == QString{"sauce"});
} Works for me (test code copied verbatim, added mock QString):
|
This does work with your mock QString, but doesn't work with the real QString from the Qt library. QString implements a bunch of operator<< and I'm not sure if it's effecting catch. |
Please provide an SSCCE, because you're doing something quite fishy by the looks of it |
Sure no problem. What platform are you on? So I can provide instructions. Are you ever used the Qt framework? |
The example should be platform-independent (I'm on Windows) Also, try not to use Qt to achieve the minimal code sample to reproduce the bug |
You can cast a QString to a std::string with QString::toLocal8Bit().constData(). This passes. It's kinda dirty & the string loses encoding (you have to use QTextCodec::codecForLocale() to handle unicode), but it works at least. |
On that note we could probably use QString().toStdString() instead. |
For sure. We have QString::fromStdString, not having one for the other direction seems wrong. |
@vpicaver look who it is!!! :) I just stumbled on this too |
@vpicaver I found these operators already defined in our project in std::ostream& operator << ( std::ostream& os, QString const& value ) {
os << value.toStdString();
return os;
}
std::ostream& operator << ( std::ostream& os, QVariant const& value ) {
os << value.toString();
return os;
} Because of these, when I tried to implement them in dewalls test cases, I got a duplicate symbol error from the linker. (of course that seems horribly wrong, it doesn't seem right for qbs to build the main project modules into my submodule tests) Did you have the same error? Maybe that's why you thought some of the I checked in QString and it only implements |
@vpicaver alas you were right. Even when I built dewalls separately with the operators defined, it didn't work. |
Is it just me or do C++ compilers have major problems picking the right overloaded method in some cases? I've seen C++ compilers get confused about overloaded methods that Java never would |
cough Read The International Standard if you think the compilers are getting confused. And no, you haven't seen them get confused. |
I'm not doubting that the standard is correct. But it's been long known that many compilers don't completely conform to the standard, or at least have had bugs at some point. For instance: http://stackoverflow.com/questions/25126987/intel-c-compiler-bug-in-member-function-overload-resolution-involving-using Given that QString has no inheritance hierarchy nor templates, and that the |
Aha, I found something that works! So in /// Overload (not specialise) this template for custom typs that you don't want
/// to provide an ostream overload for.
template<typename T>
std::string toString( T const& value ) {
return StringMaker<T>::convert( value );
} But lo and behold, specializing the template worked for me: #ifndef TOSTRINGS_H
#define TOSTRINGS_H
#include "../lib/catch.hpp"
#include <string>
#include <QString>
namespace Catch {
template<> std::string toString<QString>(QString const& s);
}
#endif // TOSTRINGS_H
#include "tostrings.h"
namespace Catch {
template<> std::string toString<QString>(QString const& s) {
return s.toLocal8Bit().constData();
}
} In a test file, I CHECK( QString("a") == QString("b") ); Output:
|
Sweet, I need to try that out! It's weird because I thought I implemented a On Saturday, December 5, 2015, Andy Edwards notifications@github.com
|
@vpicaver yeah, well as I said, implementing it as an overload didn't work...only specializing the template (despite that catch.hpp says not to) worked for me |
Well, specializing the template didn't work in MSVC2013, the Linker complained that there were multiple symbols for that function. |
I put the comment there about overloading, rather than specialising, because (a) being consistent seemed more reliable in general and (b) overloading seemed to work in cases that specialising didn't for me (although I never fully understood why in those cases). Overloading tends to be more forgiving too, and is generally the preferred approach. @jedwards1211 re the multiple symbols - did you mark your specialisation as inline? Anyway, instead of specialising |
@philsquared no, for some reason I did it non-inline...I'll have to investigate later if that caused problems, can't remember. Would you say that if it doesn't work with a given compiler/linker, then it means there's a bug in the compiler? |
TBH this is an area I get a little hazy on (perhaps @PureAbstract will drop in to clear things up?). But I believe there are two ways this can trip up: (1) is to do with two-phase lookup and so non-conformance in this area (I'm looking at you, MSVC) may yield different results than a conforming compiler (and so it would be fair to classify it as a bug - albeit one of, known, non-conformance). But (2) is to do with an aspect of implementation defined behaviour that governs the timing of when dependent instantiations are fully resolved. This is the one I'm hazier on - I don't even remember the details well enough to describe it now - I just know I've hit it in the past where different compilers may end up putting templates together in different ways - or not compiling - but all in adherence to the standard! I don't know whether that one is at play here - more likely to be 2PL. |
Well, since you ask...my preference is to specialise the There are a bunch of issues here (I made some detailed notes on this a while back but can't seem to lay my hands on them right now) - but Herb Sutter wrote an article a while back that summarises most of them quite nicely, and gives a pretty clear rationale for preferring specialising the (class|struct) template. |
@PureAbstract that is a top notch article, and taught me for the first time about which function is chosen out of a jumble of overloads and specializations. Yet it leaves me wondering more than ever why explicitly overloading |
I am going to close this, because |
I've implementing operator<< and Catch::toString for printing QString's in CHECK statements but nothing seems to work. QString is a string class from the Qt framework.
This will prints out:
CAPTURE and INFO work okay, but the expansion still returns
{?} == {?}
I also try to add
#define CATCH_CONFIG_SFINAE
it didn't seem to help.Is this a bug? Or am I doing something wrong?
The text was updated successfully, but these errors were encountered: