2

I'm newbie with C++, and also with Boost Tests. I'm using Visual C++ on Windows 7.

I have implemented these operators on the same test source file where the tests are:

std::ostream& operator<<(std::ostream& os, const std::tuple<utils::angle, utils::angle>& tuple)
{
    os << std::get<0>(tuple) << ", " << std::get<1>(tuple) << std::endl;

    return os;
}

bool operator ==(std::tuple<utils::angle, utils::angle> const &left,
    std::tuple<utils::angle, utils::angle> const &right)
{
    return (std::get<0>(left) == std::get<0>(right)) &&
        (std::get<1>(left) == std::get<1>(right));
}

The struct utils::angle has also implemented both operators in another file named Utils.cpp:

bool utils::operator ==(utils::angle const &left, utils::angle const &right)
{
    return(
        left.secs == right.secs
        && left.min == right.min
        && left.degree == right.degree);
}

std::ostream& utils::operator<<(std::ostream& os, const utils::angle& ag)
{
    os << ag.degree << "º " << ag.min << "' " << ag.secs << "\"" << std::endl;

    return os;
}

And the test that fails to compile is:

BOOST_AUTO_TEST_CASE(EquatorialToHorizonCoordinate_1)
{
    int latitude = 52;
    char orientation = 'N';
    utils::astTime hourAngle = { 5, 51, 44 };
    utils::angle declination = { 23, 13, 10 };

    utils::angle altitude = { 19, 20, 3.64 };
    utils::angle azimuth = { 283, 16, 15.70 };
    std::tuple<utils::angle, utils::angle> tuple = 
        std::make_tuple(altitude, azimuth);

    BOOST_REQUIRE_EQUAL(tuple, coord_instance.EquatorialToHorizonCoordinate(latitude, orientation, hourAngle, declination));
}

If I comment the above test and the operator<< and operator== for std::tuple<utils::angle, utils::angle> it compiles and run without any problem.

When I compile it I get this error on the output screen:

error C2338: Type has to implement operator<< to be printable note:
see reference to function template instantiation 'std::ostream
&boost::test_tools::tt_detail::impl::boost_test_print_type<R>(std::ostream
&,const T &)' being compiled
        with
        [
            R=std::tuple<utils::angle,utils::angle>,
            T=std::tuple<utils::angle,utils::angle>
        ]

And on the Visual Studio's Error Screen I get these two errors:

C2338 Type has to implement operator<< to be printable<br/>
C2679 binary '<<': no operator found which takes a right-hand operand
of type 'const T' (or there is no acceptable conversion)

There is something that I don't understand because I think I has implemented that operator.

What am I doing wrong?

UPDATE:

If I remove the operators implementation I get the same error.

I have found these "errors" on the output window:

note: or       'std::ostream &utils::operator <<(std::ostream &,const utils::astTime &)' [found using argument-dependent lookup]
note: or       'std::ostream &utils::operator <<(std::ostream &,const utils::dateTime &)' [found using argument-dependent lookup]
note: or       'std::ostream &utils::operator <<(std::ostream &,const utils::angle &)' [found using argument-dependent lookup]

It is something about ADL.

All the Output window content is here:

1>------ Rebuild All started: Project: AstroLibrary, Configuration: Debug Win32 ------
1>AstroTime.cpp
1>d:\sources\repos\myProject\v2\astrolibraries\astrotime\astrotime.cpp(142): warning C4244: 'return': conversion from 'double' to 'unsigned int', possible loss of data
1>d:\sources\repos\myProject\v2\astrolibraries\astrotime\astrotime.cpp(181): warning C4838: conversion from 'unsigned int' to 'double' requires a narrowing conversion
1>d:\sources\repos\myProject\v2\astrolibraries\astrotime\astrotime.cpp(181): warning C4838: conversion from 'unsigned int' to 'int' requires a narrowing conversion
1>d:\sources\repos\myProject\v2\astrolibraries\astrotime\astrotime.cpp(386): warning C4838: conversion from 'int' to 'double' requires a narrowing conversion
1>CoordinateSystems.cpp
1>Utils.cpp
1>Generating Code...
1>AstroTime.vcxproj -> D:\sources\Repos\myProject\v2\AstroLibraries\Debug\AstroLibrary.lib
1>Done building project "AstroTime.vcxproj".
2>------ Rebuild All started: Project: AstroLibraryTest, Configuration: Debug Win32 ------
2>AstroTimeTest.cpp
2>d:\sources\repos\myProject\v2\astrolibraries\test\astrotimetest\astrotimetest.cpp(77): warning C4838: conversion from 'unsigned int' to 'int' requires a narrowing conversion
2>d:\sources\repos\myProject\v2\astrolibraries\test\astrotimetest\astrotimetest.cpp(85): warning C4838: conversion from 'unsigned int' to 'int' requires a narrowing conversion
2>d:\sources\repos\myProject\v2\astrolibraries\test\astrotimetest\astrotimetest.cpp(93): warning C4838: conversion from 'unsigned int' to 'int' requires a narrowing conversion
2>d:\sources\repos\myProject\v2\astrolibraries\test\astrotimetest\astrotimetest.cpp(276): warning C4244: 'argument': conversion from 'double' to 'int', possible loss of data
2>d:\sources\repos\myProject\v2\astrolibraries\test\astrotimetest\astrotimetest.cpp(286): warning C4244: 'argument': conversion from 'double' to 'int', possible loss of data
2>CoordinateSystemsTest.cpp
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(53): error C2338: Type has to implement operator<< to be printable
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(62): note: see reference to function template instantiation 'std::ostream &boost::test_tools::tt_detail::impl::boost_test_print_type<R>(std::ostream &,const T &)' being compiled
2>        with
2>        [
2>            R=std::tuple<utils::angle,utils::angle>,
2>            T=std::tuple<utils::angle,utils::angle>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(91): note: see reference to function template instantiation 'std::ostream &boost::test_tools::tt_detail::impl::boost_test_print_type_impl::operator ()<T>(std::ostream &,const R &) const' being compiled
2>        with
2>        [
2>            T=std::tuple<utils::angle,utils::angle>,
2>            R=std::tuple<utils::angle,utils::angle>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(84): note: while compiling class template member function 'void boost::test_tools::tt_detail::print_log_value<T>::operator ()(std::ostream &,const T &)'
2>        with
2>        [
2>            T=std::tuple<utils::angle,utils::angle>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(220): note: see reference to function template instantiation 'void boost::test_tools::tt_detail::print_log_value<T>::operator ()(std::ostream &,const T &)' being compiled
2>        with
2>        [
2>            T=std::tuple<utils::angle,utils::angle>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(220): note: see reference to class template instantiation 'boost::test_tools::tt_detail::print_log_value<T>' being compiled
2>        with
2>        [
2>            T=std::tuple<utils::angle,utils::angle>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\utils\lazy_ostream.hpp(67): note: see reference to function template instantiation 'std::ostream &boost::test_tools::tt_detail::operator <<<Arg0>(std::ostream &,const boost::test_tools::tt_detail::print_helper_t<Arg0> &)' being compiled
2>        with
2>        [
2>            Arg0=std::tuple<utils::angle,utils::angle>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\utils\lazy_ostream.hpp(66): note: while compiling class template member function 'std::ostream &boost::unit_test::lazy_ostream_impl<boost::unit_test::lazy_ostream,boost::test_tools::tt_detail::print_helper_t<Arg0>,const T &>::operator ()(std::ostream &) const'
2>        with
2>        [
2>            Arg0=std::tuple<utils::angle,utils::angle>,
2>            T=boost::test_tools::tt_detail::print_helper_t<std::tuple<utils::angle,utils::angle>>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\old\impl.hpp(92): note: see reference to class template instantiation 'boost::unit_test::lazy_ostream_impl<boost::unit_test::lazy_ostream,boost::test_tools::tt_detail::print_helper_t<Arg0>,const T &>' being compiled
2>        with
2>        [
2>            Arg0=std::tuple<utils::angle,utils::angle>,
2>            T=boost::test_tools::tt_detail::print_helper_t<std::tuple<utils::angle,utils::angle>>
2>        ]
2>d:\sources\repos\myProject\v2\astrolibraries\test\astrotimetest\coordinatesystemstest.cpp(96): note: see reference to function template instantiation 'bool boost::test_tools::tt_detail::check_frwd<boost::test_tools::tt_detail::equal_impl_frwd,std::tuple<utils::angle,utils::angle>,std::tuple<utils::angle,utils::angle>>(Pred,const boost::unit_test::lazy_ostream &,boost::unit_test::const_string,size_t,boost::test_tools::tt_detail::tool_level,boost::test_tools::tt_detail::check_type,const Arg0 &,const char *,const Arg1 &,const char *)' being compiled
2>        with
2>        [
2>            Pred=boost::test_tools::tt_detail::equal_impl_frwd,
2>            Arg0=std::tuple<utils::angle,utils::angle>,
2>            Arg1=std::tuple<utils::angle,utils::angle>
2>        ]
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(55): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const T' (or there is no acceptable conversion)
2>        with
2>        [
2>            T=std::tuple<utils::angle,utils::angle>
2>        ]
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(508): note: could be 'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_streambuf<char,std::char_traits<char>> *)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(480): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(const void *)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(460): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(long double)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(440): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(double)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(420): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(float)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(400): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned __int64)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(380): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(__int64)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(360): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned long)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(340): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(long)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(320): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned int)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(295): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(int)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(275): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(unsigned short)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(241): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(short)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(221): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(bool)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(215): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::ios_base &(__cdecl *)(std::ios_base &))'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(209): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_ios<char,std::char_traits<char>> &(__cdecl *)(std::basic_ios<char,std::char_traits<char>> &))'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(204): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::basic_ostream<char,std::char_traits<char>>::operator <<(std::basic_ostream<char,std::char_traits<char>> &(__cdecl *)(std::basic_ostream<char,std::char_traits<char>> &))'
2>d:\sources\repos\myProject\v2\astrolibraries\astrotime\utils.h(14): note: or       'std::ostream &utils::operator <<(std::ostream &,const utils::astTime &)' [found using argument-dependent lookup]
2>d:\sources\repos\myProject\v2\astrolibraries\astrotime\utils.h(26): note: or       'std::ostream &utils::operator <<(std::ostream &,const utils::dateTime &)' [found using argument-dependent lookup]
2>d:\sources\repos\myProject\v2\astrolibraries\astrotime\utils.h(36): note: or       'std::ostream &utils::operator <<(std::ostream &,const utils::angle &)' [found using argument-dependent lookup]
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(702): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(749): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(787): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const char *)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(834): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,char)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(960): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const signed char *)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(967): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,signed char)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(974): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const unsigned char *)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(981): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,unsigned char)'
2>c:\program files (x86)\microsoft visual studio\2017\enterprise\vc\tools\msvc\14.16.27023\include\ostream(1047): note: or       'std::basic_ostream<char,std::char_traits<char>> &std::operator <<<char,std::char_traits<char>>(std::basic_ostream<char,std::char_traits<char>> &,const std::error_code &)'
2>d:\main\vcpkg-master\installed\x86-windows\include\boost\test\tools\detail\print_helper.hpp(55): note: while trying to match the argument list '(std::ostream, const T)'
2>        with
2>        [
2>            T=std::tuple<utils::angle,utils::angle>
2>        ]
2>test_main.cpp
2>Generating Code...
2>Done building project "AstroTimeTest.vcxproj" -- FAILED.
========== Rebuild All: 1 succeeded, 1 failed, 0 skipped ==========

UPDATE 2
I have this another test on the same source test file:

BOOST_AUTO_TEST_CASE(DecimalDegreesToDegrees_1)
{
    double decDegrees = 182.524167;
    utils::angle degrees = { 182, 31, 27.0 };

    BOOST_REQUIRE_EQUAL(degrees, coord_instance.DecimalDegreesToDegrees(decDegrees));
}

It works fine: it compiles and run without any error.

UPDATE 3

If I use my own struct, utils::altazm, and I don't use std::tuple it works.

VansFannel
  • 45,055
  • 107
  • 359
  • 626
  • 1
    `tuple`s are already comparable, you don't need to (and should not) provide `operator==`. – François Andrieux Feb 04 '20 at 18:50
  • Are you sure the `operator<<` you define is visible where it is used? – François Andrieux Feb 04 '20 at 18:52
  • fwiw here is the implementation of boost_test_print_type, I was curious to see what it does, turned out it simply calls the streams `operator<<` : https://www.boost.org/doc/libs/1_69_0/boost/test/tools/detail/print_helper.hpp – 463035818_is_not_an_ai Feb 04 '20 at 18:54
  • 2
    It looks like an issue with ADL. You have defined an operator, but the namespace you have declared it in is not searched. Since you cannot add it to `std`, try adding it to `utils` namespace. – Yksisarvinen Feb 04 '20 at 18:54
  • @FrançoisAndrieux As you can read in my question: "I have implemented these operators on the same test source file where the tests are". The implementation and the tests are on the same .cpp file. – VansFannel Feb 04 '20 at 18:56
  • @FrançoisAndrieux Read my question update. If I remove operators implementation I get the same error. This is why I have added. – VansFannel Feb 04 '20 at 18:57
  • @VansFannel but the operator is called inside `boost_test_print_type`, not in your test. Perhaps try to see what happens when you do call the operator directly in your test – 463035818_is_not_an_ai Feb 04 '20 at 18:57
  • @Yksisarvinen I think you are right, but I don't understand what you mean with your comment. There are three errors like this in the output window: `note: or 'std::ostream &utils::operator <<(std::ostream &,const utils::astTime &)' [found using argument-dependent lookup]` – VansFannel Feb 04 '20 at 19:10
  • You say *"The struct utils::angle has also implemented both operators in another file named Utils.cpp:"* but this doesn't mean that they are visible from where the tests execute. Are they declared in a header? Is that header included where the tests happen? Are they declared/defined in the right namespace? – François Andrieux Feb 04 '20 at 19:15
  • @FrançoisAndrieux Everything works fine before I add that test and implementations. I have another test that compare two `utils::angle` and it compiles and run fine. – VansFannel Feb 04 '20 at 19:16
  • @FrançoisAndrieux The problem is related to what Yksisarvinen said about ADL. I'm trying to find it by myself: https://en.cppreference.com/w/cpp/language/adl – VansFannel Feb 04 '20 at 19:22
  • @VansFannel That seems right. If that's the case, the problem isn't related to boost. You will encounter this problem every time you try to print your tuple in another namespace. As far as I know you can't add anything to `std` that isn't a specialization. And since every operand is in `std` that's where you would need to have your operator. Your best bet might be to wrap your tuple in a basic `struct` that is defined in the same namespace. Edit : You could put your `operator<<` in the global namespace, but you risk collisions by doing that. – François Andrieux Feb 04 '20 at 19:30
  • @FrançoisAndrieux Ok. I'll do that. – VansFannel Feb 04 '20 at 19:32
  • @VansFannel It has just occurred to me that your `operator<<` *is* a specialization so you might be allowed to add it to `std`. I'll check. Edit : I think that becomes explicitly illegal in c++20. – François Andrieux Feb 04 '20 at 19:35
  • @FrançoisAndrieux If I use my own struct, `utils::altazm`, and I don't use `std::tuple` it works. Maybe I'm very newbie to understand what it is happening. – VansFannel Feb 04 '20 at 19:40
  • @VansFannel I was mistaken. ADL should include the namespaces of template arguments used by the arguments so it should find your `operator<<`. I can't explain why it didn't work. – François Andrieux Feb 04 '20 at 19:47

0 Answers0