6

For example, say we have this class which we want to test:

struct TestMe {
  vector<int> getSomething();
}

And the test function is made of:

...
vector<int> Expected;
TestMe TM;
...
Result = TM.getSomething();
BOOST_CHECK_EQUAL(Result, Expected);
...

STL vector provides a free operator==, but it does not provide an operator <<, so this code does not compile. How can I get this to work? Can i define my own operator << ? What would its implementation look like? Extra credit to the most generic solution :)

zr.
  • 7,528
  • 11
  • 50
  • 84
  • There's no such thing as an `operator< <`, do you mean `operator<` or `operator<<`? – bdonlan Jan 29 '11 at 13:40
  • I suppose `get` is supposed to be `getSomething`. What does `operator<<` have to do with anything? `BOOST_CHECK_EQUAL` uses the `==` operator. – Potatoswatter Jan 29 '11 at 13:59
  • @Potato: Yes, but if the check fails, it tries to print out the two values using `operator<<`. Thus `BOOST_CHECK_EQUAL` requires both `operator==` and `operator<<`. – Philipp Jan 29 '11 at 14:25

3 Answers3

8

I think you should use BOOST_CHECK_EQUAL_COLLECTIONS, this tests each element and also prints where the mismatches are:

BOOST_CHECK_EQUAL_COLLECTIONS(Result.begin(), Result.end(), Expected.begin(), Expected.end());
Philipp
  • 48,066
  • 12
  • 84
  • 109
1

I think Philipp's answer is the best answer. However you can make your own templated operator<<() that will work for vectors and other standard containers if you want:

// Will write out any container that has begin(), end() and a const_iterator type
template <typename C>
std::ostream& output_container(std::ostream& os, C const& c) {
    for (typename C::const_iterator i = c.begin(); i != c.end(); ++i) {
        if (i != c.begin()) os << ", ";
        os << *i;
    }

    return os;
}

// Overload operators for each container type that forward to output_container()
template <typename T>
std::ostream& operator<<(std::ostream& os, vector<T> const& c) {
    return output_container(os, c);
}

template <typename T>
std::ostream& operator<<(std::ostream& os, list<T> const& c) {
    return output_container(os, c);
}

Although you could simply rename output_container() to operator<<() and get rid of the per-container-type operator<<() templates, thereby catching all attempts to use << on a class type, this could possibly interfere with operator<<() function templates for other types.

Community
  • 1
  • 1
j_random_hacker
  • 50,331
  • 10
  • 105
  • 169
  • I tried a very similar solution before posting my question, but it did not compile. I copy-pasted your solution and get the same error: error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'const std::vector<_Ty>' (or there is no acceptable conversion) 1> with 1> [ 1> _Ty=uint8_t 1> ] – zr. Jan 29 '11 at 14:56
  • @zr: It sounds like name lookup is failing. Are you sure that all these templates are defined before they are used? – j_random_hacker Jan 29 '11 at 15:04
  • @zr: Also it looks like you're actually using a `vector`, not `vector` as advertised -- is that so? Otherwise I'm confused. – j_random_hacker Jan 29 '11 at 15:07
  • @JRH: The answer to both questions is yes. In the example i used an int for simplicity. – zr. Jan 29 '11 at 15:17
  • @zr: I suspect the problem is that `BOOST_CHECK_EQUAL()` expands to a call to a template function (let's call it `f()`) which calls `operator<<()`, and that *at the point `f()` was defined*, our `operator<<()` template was not. If that's the case, then you'll need to put a forward declaration (`template std::ostream& operator<<(std::ostream&, std::vector const&);`) *before* #including the Boost headers that define `BOOST_CHECK_EQUAL()`. (I know, yuck.) – j_random_hacker Jan 29 '11 at 15:42
  • @zr @j_random_hacker: `Boost` defines free function `operator<<`s like `template< class C, class T > basic_wrap_stringstream& operator<<( basic_wrap_stringstream&, T const& )` in `namespace boost`. So, compiler can't find your `operator<<` in global scope because of ADL. If we enclose our `operator<<` by `namespace std`, the compiler will find the operator. However, according to 17.4.3.1 in the standard, this results in undefined behaviour unfortunately... – Ise Wisteria Jan 29 '11 at 20:38
  • @Ise: That's useful to know, but it looks like that overload requires a `basic_wrap_stringstream`, which will require an implicit conversion, making it less specialised than my `operator<<()`. But I don't believe that's the underlying problem anyway, because if it was then the compiler would find that Boost's overload when my template is absent, and when my template is present the result would be either (a) the compiler still prefers the Boost overload or (b) an "ambiguity" error message, not a "no operator found" message. – j_random_hacker Jan 30 '11 at 09:06
  • @zr @j_random_hacker: It's difficult to describe in a comment, but... `Boost test library` is defined in `namespace boost`. So if the compiler sees an `operator<<`, first the compiler searches in `namespace boost`, and finds candidates. If `boost test library` isn't defined in `namespace boost`, or if there aren't candidates, the compiler will search in global scope. Sorry, probably I can't explain in more detail in a comment. – Ise Wisteria Jan 30 '11 at 10:01
  • @Ise: Thanks, but I *suspect* that's not quite right after grovelling through 14.6.4.2 and 3.4.2 in the standard. It seems that, provided the name doesn't turn out to be a method, both "ordinary" lookup and lookup in associated namespaces and classes (e.g. in namespace `boost`) will take place, and overload resolution will take place on the *union* of all names found. I can't spend more time on this unfortunately, but thanks for your input. – j_random_hacker Jan 30 '11 at 11:22
0

I was looking for something similar, a way to customize the output string to print integers in hex. Injecting an operator into the std namespace would work, but every BOOST_CHECK in my test would be printed in hex.

So I injected some custom operators in the boost namespace that I could control with some global bools.

See my answer here boost-check-fails-to-compile-operator-for-custom-types.

Community
  • 1
  • 1
Nick
  • 2,342
  • 28
  • 25