Skip to content
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

Print vector content. #170

Closed
slepasteur opened this issue Dec 20, 2018 · 3 comments
Closed

Print vector content. #170

slepasteur opened this issue Dec 20, 2018 · 3 comments

Comments

@slepasteur
Copy link

slepasteur commented Dec 20, 2018

Description

I am trying to print std::vector content on failure.
E.g.:
REQUIRE(std::vector<int>{1} == std::vector<int>{1,2});

Should produce to following output.

FATAL ERROR: REQUIRE( std::vector<int>{1} == std::vector<int>{1,2} ) is NOT correct!
  values: REQUIRE( [ 1 ] == [ 1 2 ] )

Here is my attempt:

namespace doctest {
template <typename T>
struct StringMaker<std::vector<T>>
{
    static String convert(const std::vector<T>& vec)
    {
        std::ostringstream oss;
        oss << "[ ";
        std::copy(vec.begin(), vec.end(), std::ostream_iterator<T>(oss, " "));
        oss << "]";
        return oss.str().c_str();
    }
};
} // namespace doctest

It works well at first but as soon as I add more translation units with more tests it starts failing and printing the default way:

FATAL ERROR: REQUIRE( std::vector<int>{1} == std::vector<int>{1,2} ) is NOT correct!
  values: REQUIRE( {?} == {?} )

Steps to reproduce

It is kind of hard to reproduce as the output is shown only on failure and it keeps failing after some time.

Extra information

  • doctest version: v2.0.1
  • Operating System: Archlinux
  • Compiler+version: clang 7.0.0 / gcc 8.2.1
@onqtam
Copy link
Member

onqtam commented Dec 20, 2018

Is the specialization of StringMaker<std::vector<T>> visible in all translation units? It should be - not just in one of them. Perhaps you can make a proxy header for doctest called doctest_proxy.h with the following:

// doctest_proxy.h

#pragma once

#include <doctest.h>

// the specialization of StringMaker<std::vector<T>>

and include it instead of the framework header directly.

Perhaps I should edit the documentation if this is the problem (the specialization being present in only one of the translation units) - this might be due to ODR.

@slepasteur
Copy link
Author

That was indeed the problem. Thank-you.

@u3shit
Copy link

u3shit commented Apr 20, 2021

Should I suggest some documentation changes wrt this issue? I've spent numerous hours trying to figure out why my custom stringification functions seem to randomly work in some files but not in others (well, I learned that you can do ODR violations with function overloads and template specializations, so it wasn't a completely wasted time, but well...).
I think the documentation should mention that if there is a specialzation in one translation unit, but on in the other and in the other you print the same type of variable, that's an ODR violation. And maybe some suggestions how to avoid it, like the wrapper header above (but it's not perfect either because a) that would force you to include a bunch of stl headers even in files you don't need them and b) won't work if you have exteral code that happen to use doctest). For your own types, you could avoid this issue by making sure to always declare the toString function in the header, next to the class and not in random c++ files. (Incidentally, can we forward declare classes from doctest? Like namespace doctest { class String; }, I'd rather not pull in the whole doctest header just for that in my headers.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants