Can't stream std::endl with overloaded operator<<() for std::variant

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
6
down vote

favorite
1












This answer describes how to stream a standalone std::variant. However, it doesn't seem to work when std::variant is stored in a std::unordered_map.



The following example:



#include <iostream>
#include <string>
#include <variant>
#include <complex>
#include <unordered_map>

// https://stackoverflow.com/a/46893057/8414561
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::variant<Ts...>& v)

std::visit([&os](auto&& arg)
os << arg;
, v);
return os;


int main()

using namespace std::complex_literals;
std::unordered_map<int, std::variant<int, std::string, double, std::complex<double>>> map
0, 4,
1, "hello",
2, 3.14,
3, 2. + 3i
;

for (const auto& [key, value] : map)
std::cout << key << "=" << value << std::endl;



fails to compile with:



In file included from main.cpp:3:
/usr/local/include/c++/8.1.0/variant: In instantiation of 'constexpr const bool std::__detail::__variant::_Traits<>::_S_default_ctor':
/usr/local/include/c++/8.1.0/variant:1038:11: required from 'class std::variant<>'
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:300:4: error: invalid use of incomplete type 'struct std::__detail::__variant::_Nth_type<0>'
is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/c++/8.1.0/variant:58:12: note: declaration of 'struct std::__detail::__variant::_Nth_type<0>'
struct _Nth_type;
^~~~~~~~~
/usr/local/include/c++/8.1.0/variant: In instantiation of 'class std::variant<>':
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:1051:39: error: static assertion failed: variant must have at least one alternative
static_assert(sizeof...(_Types) > 0,
~~~~~~~~~~~~~~~~~~^~~


Why does it happen? How is it possible to fix it?










share|improve this question























  • For whatever reason your overload of << is a better match for std::cout << std::endl than the standard std::osteam& std::operator<<(std::ostream&, std::ostream&(*pf)(std::ostream&)).
    – 0x499602D2
    2 hours ago










  • This is an unfortunate choice of title. Do you mind changing it so it reflects the real issue?
    – Passer By
    1 hour ago










  • More or less: "can't stream std::endl with overloaded stream operator for std::variant". The problem has nothing to do with the map.
    – Passer By
    1 hour ago















up vote
6
down vote

favorite
1












This answer describes how to stream a standalone std::variant. However, it doesn't seem to work when std::variant is stored in a std::unordered_map.



The following example:



#include <iostream>
#include <string>
#include <variant>
#include <complex>
#include <unordered_map>

// https://stackoverflow.com/a/46893057/8414561
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::variant<Ts...>& v)

std::visit([&os](auto&& arg)
os << arg;
, v);
return os;


int main()

using namespace std::complex_literals;
std::unordered_map<int, std::variant<int, std::string, double, std::complex<double>>> map
0, 4,
1, "hello",
2, 3.14,
3, 2. + 3i
;

for (const auto& [key, value] : map)
std::cout << key << "=" << value << std::endl;



fails to compile with:



In file included from main.cpp:3:
/usr/local/include/c++/8.1.0/variant: In instantiation of 'constexpr const bool std::__detail::__variant::_Traits<>::_S_default_ctor':
/usr/local/include/c++/8.1.0/variant:1038:11: required from 'class std::variant<>'
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:300:4: error: invalid use of incomplete type 'struct std::__detail::__variant::_Nth_type<0>'
is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/c++/8.1.0/variant:58:12: note: declaration of 'struct std::__detail::__variant::_Nth_type<0>'
struct _Nth_type;
^~~~~~~~~
/usr/local/include/c++/8.1.0/variant: In instantiation of 'class std::variant<>':
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:1051:39: error: static assertion failed: variant must have at least one alternative
static_assert(sizeof...(_Types) > 0,
~~~~~~~~~~~~~~~~~~^~~


Why does it happen? How is it possible to fix it?










share|improve this question























  • For whatever reason your overload of << is a better match for std::cout << std::endl than the standard std::osteam& std::operator<<(std::ostream&, std::ostream&(*pf)(std::ostream&)).
    – 0x499602D2
    2 hours ago










  • This is an unfortunate choice of title. Do you mind changing it so it reflects the real issue?
    – Passer By
    1 hour ago










  • More or less: "can't stream std::endl with overloaded stream operator for std::variant". The problem has nothing to do with the map.
    – Passer By
    1 hour ago













up vote
6
down vote

favorite
1









up vote
6
down vote

favorite
1






1





This answer describes how to stream a standalone std::variant. However, it doesn't seem to work when std::variant is stored in a std::unordered_map.



The following example:



#include <iostream>
#include <string>
#include <variant>
#include <complex>
#include <unordered_map>

// https://stackoverflow.com/a/46893057/8414561
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::variant<Ts...>& v)

std::visit([&os](auto&& arg)
os << arg;
, v);
return os;


int main()

using namespace std::complex_literals;
std::unordered_map<int, std::variant<int, std::string, double, std::complex<double>>> map
0, 4,
1, "hello",
2, 3.14,
3, 2. + 3i
;

for (const auto& [key, value] : map)
std::cout << key << "=" << value << std::endl;



fails to compile with:



In file included from main.cpp:3:
/usr/local/include/c++/8.1.0/variant: In instantiation of 'constexpr const bool std::__detail::__variant::_Traits<>::_S_default_ctor':
/usr/local/include/c++/8.1.0/variant:1038:11: required from 'class std::variant<>'
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:300:4: error: invalid use of incomplete type 'struct std::__detail::__variant::_Nth_type<0>'
is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/c++/8.1.0/variant:58:12: note: declaration of 'struct std::__detail::__variant::_Nth_type<0>'
struct _Nth_type;
^~~~~~~~~
/usr/local/include/c++/8.1.0/variant: In instantiation of 'class std::variant<>':
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:1051:39: error: static assertion failed: variant must have at least one alternative
static_assert(sizeof...(_Types) > 0,
~~~~~~~~~~~~~~~~~~^~~


Why does it happen? How is it possible to fix it?










share|improve this question















This answer describes how to stream a standalone std::variant. However, it doesn't seem to work when std::variant is stored in a std::unordered_map.



The following example:



#include <iostream>
#include <string>
#include <variant>
#include <complex>
#include <unordered_map>

// https://stackoverflow.com/a/46893057/8414561
template<typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::variant<Ts...>& v)

std::visit([&os](auto&& arg)
os << arg;
, v);
return os;


int main()

using namespace std::complex_literals;
std::unordered_map<int, std::variant<int, std::string, double, std::complex<double>>> map
0, 4,
1, "hello",
2, 3.14,
3, 2. + 3i
;

for (const auto& [key, value] : map)
std::cout << key << "=" << value << std::endl;



fails to compile with:



In file included from main.cpp:3:
/usr/local/include/c++/8.1.0/variant: In instantiation of 'constexpr const bool std::__detail::__variant::_Traits<>::_S_default_ctor':
/usr/local/include/c++/8.1.0/variant:1038:11: required from 'class std::variant<>'
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:300:4: error: invalid use of incomplete type 'struct std::__detail::__variant::_Nth_type<0>'
is_default_constructible_v<typename _Nth_type<0, _Types...>::type>;
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/include/c++/8.1.0/variant:58:12: note: declaration of 'struct std::__detail::__variant::_Nth_type<0>'
struct _Nth_type;
^~~~~~~~~
/usr/local/include/c++/8.1.0/variant: In instantiation of 'class std::variant<>':
main.cpp:27:50: required from here
/usr/local/include/c++/8.1.0/variant:1051:39: error: static assertion failed: variant must have at least one alternative
static_assert(sizeof...(_Types) > 0,
~~~~~~~~~~~~~~~~~~^~~


Why does it happen? How is it possible to fix it?







c++ c++17 variant






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 1 hour ago

























asked 3 hours ago









Dev Null

1,687721




1,687721











  • For whatever reason your overload of << is a better match for std::cout << std::endl than the standard std::osteam& std::operator<<(std::ostream&, std::ostream&(*pf)(std::ostream&)).
    – 0x499602D2
    2 hours ago










  • This is an unfortunate choice of title. Do you mind changing it so it reflects the real issue?
    – Passer By
    1 hour ago










  • More or less: "can't stream std::endl with overloaded stream operator for std::variant". The problem has nothing to do with the map.
    – Passer By
    1 hour ago

















  • For whatever reason your overload of << is a better match for std::cout << std::endl than the standard std::osteam& std::operator<<(std::ostream&, std::ostream&(*pf)(std::ostream&)).
    – 0x499602D2
    2 hours ago










  • This is an unfortunate choice of title. Do you mind changing it so it reflects the real issue?
    – Passer By
    1 hour ago










  • More or less: "can't stream std::endl with overloaded stream operator for std::variant". The problem has nothing to do with the map.
    – Passer By
    1 hour ago
















For whatever reason your overload of << is a better match for std::cout << std::endl than the standard std::osteam& std::operator<<(std::ostream&, std::ostream&(*pf)(std::ostream&)).
– 0x499602D2
2 hours ago




For whatever reason your overload of << is a better match for std::cout << std::endl than the standard std::osteam& std::operator<<(std::ostream&, std::ostream&(*pf)(std::ostream&)).
– 0x499602D2
2 hours ago












This is an unfortunate choice of title. Do you mind changing it so it reflects the real issue?
– Passer By
1 hour ago




This is an unfortunate choice of title. Do you mind changing it so it reflects the real issue?
– Passer By
1 hour ago












More or less: "can't stream std::endl with overloaded stream operator for std::variant". The problem has nothing to do with the map.
– Passer By
1 hour ago





More or less: "can't stream std::endl with overloaded stream operator for std::variant". The problem has nothing to do with the map.
– Passer By
1 hour ago













3 Answers
3






active

oldest

votes

















up vote
9
down vote













In [temp.arg.explicit]/3, we have this amazing sentence:




A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments.




What does this mean? What is a trailing template parameter pack? What does not otherwise deduced mean? These are all good questions that don't really have answers. But this has very interesting consequences. Consider:



template <typename... Ts> void f(std::tuple<Ts...>);
f(); // ok??


This is... well-formed. We can't deduce Ts... so we deduce it as empty. That leaves us with std::tuple<>, which is a perfectly valid type - and a perfectly valid type that can even be instantiated with . So this compiles!



So what happens when the thing we deduce from the empty parameter pack we conjured up isn't a valid type? Here's an example:



template <class... Ts>
struct Y

static_assert(sizeof...(Ts)>0, "!");
;


template <class... Ts>
std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )

return os << std::endl;



The operator<< is a potential candidate, but deduction fails... or so it would seem. Until we conjure up Ts... as empty. But Y<> is an invalid type! We don't even try to find out that we can't construct a Y<> from std::endl - we have already failed.



This is fundamentally the same situation you have with variant, because variant<> is not a valid type.



The easy fix is to simply change your function template from taking a variant<Ts...> to a variant<T, Ts...>. This can no longer deduce to variant<>, which isn't even a possible thing, so we don't have a problem.






share|improve this answer




















  • Or ,std::enable_if_t< 0<sizeof...(Ts), bool> = true> SFINAE. Because typing T0, Ts... is annoying. ;)
    – Yakk - Adam Nevraumont
    1 hour ago










  • Excellent catch. Even seems like a useful feature (except when it catches you off guard). Can't variant<> by implemented in a SFINAE friendly way?
    – alfC
    1 hour ago










  • @alfC I honestly view it as more of a language bug than a library bug
    – Barry
    1 hour ago










  • @alfC It can't
    – Passer By
    1 hour ago






  • 1




    I feel like this answer raised more questions then it answers, if you attempt this with other types it does not fail in this way. Why it is attempting this deduction for std::endl but not other cases? or if it is attempting the deduction in other cases then why is it valid for other cases? I have to wonder if this is really the intended behavior, it feesl like a very surprising trap.
    – Shafik Yaghmour
    1 hour ago


















up vote
6
down vote













For some reason, your code (which looks correct to me) is trying to instantiate std::variant<> (empty alternatives) both in clang and gcc.



The workaround I found is to make a template for a specifically non-empty variant.
Since std::variant cannot be empty anyway, I think it is usually good to write generic functions for non-empty variants.



template<typename T, typename... Ts>
std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)

std::visit([&os](auto&& arg)
os << arg;
, v);
return os;



With this change, your code works for me.






share|improve this answer



























    up vote
    4
    down vote













    The problem is the std::endl but I am puzzled why your overload is a better match than the one from std::basic_ostream::operator<<, see godbolt live example:



    <source>:29:12: note: in instantiation of template class 'std::variant<>' requested here
    << std::endl;
    ^


    and removing the std::endl indeed fixes the problem, see it live on Wandbox.



    As alfC points out altering your operator to disallow an empty variant does indeed fix the issue, see it live:



    template<typename T, typename... Ts>
    std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)





    share|improve this answer






















    • In my experiment, the code fails whether you have the std::endl or not. (and whether you have the "="). gcc 8.1/clang 6.0.
      – alfC
      2 hours ago










    • @alfC the wandbox example I link to shows it working w/o the endl.
      – Shafik Yaghmour
      2 hours ago











    • Ah, yes you are right. (I have a std::cout << std::endl somewhere else in the test code). It looks as if std::variant<> has an implicit contructor from anything?, maybe it is a bug in the implementation of std::variant?
      – alfC
      2 hours ago










    Your Answer





    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52845621%2fcant-stream-stdendl-with-overloaded-operator-for-stdvariant%23new-answer', 'question_page');

    );

    Post as a guest






























    3 Answers
    3






    active

    oldest

    votes








    3 Answers
    3






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    9
    down vote













    In [temp.arg.explicit]/3, we have this amazing sentence:




    A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments.




    What does this mean? What is a trailing template parameter pack? What does not otherwise deduced mean? These are all good questions that don't really have answers. But this has very interesting consequences. Consider:



    template <typename... Ts> void f(std::tuple<Ts...>);
    f(); // ok??


    This is... well-formed. We can't deduce Ts... so we deduce it as empty. That leaves us with std::tuple<>, which is a perfectly valid type - and a perfectly valid type that can even be instantiated with . So this compiles!



    So what happens when the thing we deduce from the empty parameter pack we conjured up isn't a valid type? Here's an example:



    template <class... Ts>
    struct Y

    static_assert(sizeof...(Ts)>0, "!");
    ;


    template <class... Ts>
    std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )

    return os << std::endl;



    The operator<< is a potential candidate, but deduction fails... or so it would seem. Until we conjure up Ts... as empty. But Y<> is an invalid type! We don't even try to find out that we can't construct a Y<> from std::endl - we have already failed.



    This is fundamentally the same situation you have with variant, because variant<> is not a valid type.



    The easy fix is to simply change your function template from taking a variant<Ts...> to a variant<T, Ts...>. This can no longer deduce to variant<>, which isn't even a possible thing, so we don't have a problem.






    share|improve this answer




















    • Or ,std::enable_if_t< 0<sizeof...(Ts), bool> = true> SFINAE. Because typing T0, Ts... is annoying. ;)
      – Yakk - Adam Nevraumont
      1 hour ago










    • Excellent catch. Even seems like a useful feature (except when it catches you off guard). Can't variant<> by implemented in a SFINAE friendly way?
      – alfC
      1 hour ago










    • @alfC I honestly view it as more of a language bug than a library bug
      – Barry
      1 hour ago










    • @alfC It can't
      – Passer By
      1 hour ago






    • 1




      I feel like this answer raised more questions then it answers, if you attempt this with other types it does not fail in this way. Why it is attempting this deduction for std::endl but not other cases? or if it is attempting the deduction in other cases then why is it valid for other cases? I have to wonder if this is really the intended behavior, it feesl like a very surprising trap.
      – Shafik Yaghmour
      1 hour ago















    up vote
    9
    down vote













    In [temp.arg.explicit]/3, we have this amazing sentence:




    A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments.




    What does this mean? What is a trailing template parameter pack? What does not otherwise deduced mean? These are all good questions that don't really have answers. But this has very interesting consequences. Consider:



    template <typename... Ts> void f(std::tuple<Ts...>);
    f(); // ok??


    This is... well-formed. We can't deduce Ts... so we deduce it as empty. That leaves us with std::tuple<>, which is a perfectly valid type - and a perfectly valid type that can even be instantiated with . So this compiles!



    So what happens when the thing we deduce from the empty parameter pack we conjured up isn't a valid type? Here's an example:



    template <class... Ts>
    struct Y

    static_assert(sizeof...(Ts)>0, "!");
    ;


    template <class... Ts>
    std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )

    return os << std::endl;



    The operator<< is a potential candidate, but deduction fails... or so it would seem. Until we conjure up Ts... as empty. But Y<> is an invalid type! We don't even try to find out that we can't construct a Y<> from std::endl - we have already failed.



    This is fundamentally the same situation you have with variant, because variant<> is not a valid type.



    The easy fix is to simply change your function template from taking a variant<Ts...> to a variant<T, Ts...>. This can no longer deduce to variant<>, which isn't even a possible thing, so we don't have a problem.






    share|improve this answer




















    • Or ,std::enable_if_t< 0<sizeof...(Ts), bool> = true> SFINAE. Because typing T0, Ts... is annoying. ;)
      – Yakk - Adam Nevraumont
      1 hour ago










    • Excellent catch. Even seems like a useful feature (except when it catches you off guard). Can't variant<> by implemented in a SFINAE friendly way?
      – alfC
      1 hour ago










    • @alfC I honestly view it as more of a language bug than a library bug
      – Barry
      1 hour ago










    • @alfC It can't
      – Passer By
      1 hour ago






    • 1




      I feel like this answer raised more questions then it answers, if you attempt this with other types it does not fail in this way. Why it is attempting this deduction for std::endl but not other cases? or if it is attempting the deduction in other cases then why is it valid for other cases? I have to wonder if this is really the intended behavior, it feesl like a very surprising trap.
      – Shafik Yaghmour
      1 hour ago













    up vote
    9
    down vote










    up vote
    9
    down vote









    In [temp.arg.explicit]/3, we have this amazing sentence:




    A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments.




    What does this mean? What is a trailing template parameter pack? What does not otherwise deduced mean? These are all good questions that don't really have answers. But this has very interesting consequences. Consider:



    template <typename... Ts> void f(std::tuple<Ts...>);
    f(); // ok??


    This is... well-formed. We can't deduce Ts... so we deduce it as empty. That leaves us with std::tuple<>, which is a perfectly valid type - and a perfectly valid type that can even be instantiated with . So this compiles!



    So what happens when the thing we deduce from the empty parameter pack we conjured up isn't a valid type? Here's an example:



    template <class... Ts>
    struct Y

    static_assert(sizeof...(Ts)>0, "!");
    ;


    template <class... Ts>
    std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )

    return os << std::endl;



    The operator<< is a potential candidate, but deduction fails... or so it would seem. Until we conjure up Ts... as empty. But Y<> is an invalid type! We don't even try to find out that we can't construct a Y<> from std::endl - we have already failed.



    This is fundamentally the same situation you have with variant, because variant<> is not a valid type.



    The easy fix is to simply change your function template from taking a variant<Ts...> to a variant<T, Ts...>. This can no longer deduce to variant<>, which isn't even a possible thing, so we don't have a problem.






    share|improve this answer












    In [temp.arg.explicit]/3, we have this amazing sentence:




    A trailing template parameter pack not otherwise deduced will be deduced to an empty sequence of template arguments.




    What does this mean? What is a trailing template parameter pack? What does not otherwise deduced mean? These are all good questions that don't really have answers. But this has very interesting consequences. Consider:



    template <typename... Ts> void f(std::tuple<Ts...>);
    f(); // ok??


    This is... well-formed. We can't deduce Ts... so we deduce it as empty. That leaves us with std::tuple<>, which is a perfectly valid type - and a perfectly valid type that can even be instantiated with . So this compiles!



    So what happens when the thing we deduce from the empty parameter pack we conjured up isn't a valid type? Here's an example:



    template <class... Ts>
    struct Y

    static_assert(sizeof...(Ts)>0, "!");
    ;


    template <class... Ts>
    std::ostream& operator<<(std::ostream& os, Y<Ts...> const& )

    return os << std::endl;



    The operator<< is a potential candidate, but deduction fails... or so it would seem. Until we conjure up Ts... as empty. But Y<> is an invalid type! We don't even try to find out that we can't construct a Y<> from std::endl - we have already failed.



    This is fundamentally the same situation you have with variant, because variant<> is not a valid type.



    The easy fix is to simply change your function template from taking a variant<Ts...> to a variant<T, Ts...>. This can no longer deduce to variant<>, which isn't even a possible thing, so we don't have a problem.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered 2 hours ago









    Barry

    171k18291534




    171k18291534











    • Or ,std::enable_if_t< 0<sizeof...(Ts), bool> = true> SFINAE. Because typing T0, Ts... is annoying. ;)
      – Yakk - Adam Nevraumont
      1 hour ago










    • Excellent catch. Even seems like a useful feature (except when it catches you off guard). Can't variant<> by implemented in a SFINAE friendly way?
      – alfC
      1 hour ago










    • @alfC I honestly view it as more of a language bug than a library bug
      – Barry
      1 hour ago










    • @alfC It can't
      – Passer By
      1 hour ago






    • 1




      I feel like this answer raised more questions then it answers, if you attempt this with other types it does not fail in this way. Why it is attempting this deduction for std::endl but not other cases? or if it is attempting the deduction in other cases then why is it valid for other cases? I have to wonder if this is really the intended behavior, it feesl like a very surprising trap.
      – Shafik Yaghmour
      1 hour ago

















    • Or ,std::enable_if_t< 0<sizeof...(Ts), bool> = true> SFINAE. Because typing T0, Ts... is annoying. ;)
      – Yakk - Adam Nevraumont
      1 hour ago










    • Excellent catch. Even seems like a useful feature (except when it catches you off guard). Can't variant<> by implemented in a SFINAE friendly way?
      – alfC
      1 hour ago










    • @alfC I honestly view it as more of a language bug than a library bug
      – Barry
      1 hour ago










    • @alfC It can't
      – Passer By
      1 hour ago






    • 1




      I feel like this answer raised more questions then it answers, if you attempt this with other types it does not fail in this way. Why it is attempting this deduction for std::endl but not other cases? or if it is attempting the deduction in other cases then why is it valid for other cases? I have to wonder if this is really the intended behavior, it feesl like a very surprising trap.
      – Shafik Yaghmour
      1 hour ago
















    Or ,std::enable_if_t< 0<sizeof...(Ts), bool> = true> SFINAE. Because typing T0, Ts... is annoying. ;)
    – Yakk - Adam Nevraumont
    1 hour ago




    Or ,std::enable_if_t< 0<sizeof...(Ts), bool> = true> SFINAE. Because typing T0, Ts... is annoying. ;)
    – Yakk - Adam Nevraumont
    1 hour ago












    Excellent catch. Even seems like a useful feature (except when it catches you off guard). Can't variant<> by implemented in a SFINAE friendly way?
    – alfC
    1 hour ago




    Excellent catch. Even seems like a useful feature (except when it catches you off guard). Can't variant<> by implemented in a SFINAE friendly way?
    – alfC
    1 hour ago












    @alfC I honestly view it as more of a language bug than a library bug
    – Barry
    1 hour ago




    @alfC I honestly view it as more of a language bug than a library bug
    – Barry
    1 hour ago












    @alfC It can't
    – Passer By
    1 hour ago




    @alfC It can't
    – Passer By
    1 hour ago




    1




    1




    I feel like this answer raised more questions then it answers, if you attempt this with other types it does not fail in this way. Why it is attempting this deduction for std::endl but not other cases? or if it is attempting the deduction in other cases then why is it valid for other cases? I have to wonder if this is really the intended behavior, it feesl like a very surprising trap.
    – Shafik Yaghmour
    1 hour ago





    I feel like this answer raised more questions then it answers, if you attempt this with other types it does not fail in this way. Why it is attempting this deduction for std::endl but not other cases? or if it is attempting the deduction in other cases then why is it valid for other cases? I have to wonder if this is really the intended behavior, it feesl like a very surprising trap.
    – Shafik Yaghmour
    1 hour ago













    up vote
    6
    down vote













    For some reason, your code (which looks correct to me) is trying to instantiate std::variant<> (empty alternatives) both in clang and gcc.



    The workaround I found is to make a template for a specifically non-empty variant.
    Since std::variant cannot be empty anyway, I think it is usually good to write generic functions for non-empty variants.



    template<typename T, typename... Ts>
    std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)

    std::visit([&os](auto&& arg)
    os << arg;
    , v);
    return os;



    With this change, your code works for me.






    share|improve this answer
























      up vote
      6
      down vote













      For some reason, your code (which looks correct to me) is trying to instantiate std::variant<> (empty alternatives) both in clang and gcc.



      The workaround I found is to make a template for a specifically non-empty variant.
      Since std::variant cannot be empty anyway, I think it is usually good to write generic functions for non-empty variants.



      template<typename T, typename... Ts>
      std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)

      std::visit([&os](auto&& arg)
      os << arg;
      , v);
      return os;



      With this change, your code works for me.






      share|improve this answer






















        up vote
        6
        down vote










        up vote
        6
        down vote









        For some reason, your code (which looks correct to me) is trying to instantiate std::variant<> (empty alternatives) both in clang and gcc.



        The workaround I found is to make a template for a specifically non-empty variant.
        Since std::variant cannot be empty anyway, I think it is usually good to write generic functions for non-empty variants.



        template<typename T, typename... Ts>
        std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)

        std::visit([&os](auto&& arg)
        os << arg;
        , v);
        return os;



        With this change, your code works for me.






        share|improve this answer












        For some reason, your code (which looks correct to me) is trying to instantiate std::variant<> (empty alternatives) both in clang and gcc.



        The workaround I found is to make a template for a specifically non-empty variant.
        Since std::variant cannot be empty anyway, I think it is usually good to write generic functions for non-empty variants.



        template<typename T, typename... Ts>
        std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)

        std::visit([&os](auto&& arg)
        os << arg;
        , v);
        return os;



        With this change, your code works for me.







        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered 2 hours ago









        alfC

        4,79322558




        4,79322558




















            up vote
            4
            down vote













            The problem is the std::endl but I am puzzled why your overload is a better match than the one from std::basic_ostream::operator<<, see godbolt live example:



            <source>:29:12: note: in instantiation of template class 'std::variant<>' requested here
            << std::endl;
            ^


            and removing the std::endl indeed fixes the problem, see it live on Wandbox.



            As alfC points out altering your operator to disallow an empty variant does indeed fix the issue, see it live:



            template<typename T, typename... Ts>
            std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)





            share|improve this answer






















            • In my experiment, the code fails whether you have the std::endl or not. (and whether you have the "="). gcc 8.1/clang 6.0.
              – alfC
              2 hours ago










            • @alfC the wandbox example I link to shows it working w/o the endl.
              – Shafik Yaghmour
              2 hours ago











            • Ah, yes you are right. (I have a std::cout << std::endl somewhere else in the test code). It looks as if std::variant<> has an implicit contructor from anything?, maybe it is a bug in the implementation of std::variant?
              – alfC
              2 hours ago














            up vote
            4
            down vote













            The problem is the std::endl but I am puzzled why your overload is a better match than the one from std::basic_ostream::operator<<, see godbolt live example:



            <source>:29:12: note: in instantiation of template class 'std::variant<>' requested here
            << std::endl;
            ^


            and removing the std::endl indeed fixes the problem, see it live on Wandbox.



            As alfC points out altering your operator to disallow an empty variant does indeed fix the issue, see it live:



            template<typename T, typename... Ts>
            std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)





            share|improve this answer






















            • In my experiment, the code fails whether you have the std::endl or not. (and whether you have the "="). gcc 8.1/clang 6.0.
              – alfC
              2 hours ago










            • @alfC the wandbox example I link to shows it working w/o the endl.
              – Shafik Yaghmour
              2 hours ago











            • Ah, yes you are right. (I have a std::cout << std::endl somewhere else in the test code). It looks as if std::variant<> has an implicit contructor from anything?, maybe it is a bug in the implementation of std::variant?
              – alfC
              2 hours ago












            up vote
            4
            down vote










            up vote
            4
            down vote









            The problem is the std::endl but I am puzzled why your overload is a better match than the one from std::basic_ostream::operator<<, see godbolt live example:



            <source>:29:12: note: in instantiation of template class 'std::variant<>' requested here
            << std::endl;
            ^


            and removing the std::endl indeed fixes the problem, see it live on Wandbox.



            As alfC points out altering your operator to disallow an empty variant does indeed fix the issue, see it live:



            template<typename T, typename... Ts>
            std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)





            share|improve this answer














            The problem is the std::endl but I am puzzled why your overload is a better match than the one from std::basic_ostream::operator<<, see godbolt live example:



            <source>:29:12: note: in instantiation of template class 'std::variant<>' requested here
            << std::endl;
            ^


            and removing the std::endl indeed fixes the problem, see it live on Wandbox.



            As alfC points out altering your operator to disallow an empty variant does indeed fix the issue, see it live:



            template<typename T, typename... Ts>
            std::ostream& operator<<(std::ostream& os, const std::variant<T, Ts...>& v)






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited 1 hour ago

























            answered 2 hours ago









            Shafik Yaghmour

            120k23301499




            120k23301499











            • In my experiment, the code fails whether you have the std::endl or not. (and whether you have the "="). gcc 8.1/clang 6.0.
              – alfC
              2 hours ago










            • @alfC the wandbox example I link to shows it working w/o the endl.
              – Shafik Yaghmour
              2 hours ago











            • Ah, yes you are right. (I have a std::cout << std::endl somewhere else in the test code). It looks as if std::variant<> has an implicit contructor from anything?, maybe it is a bug in the implementation of std::variant?
              – alfC
              2 hours ago
















            • In my experiment, the code fails whether you have the std::endl or not. (and whether you have the "="). gcc 8.1/clang 6.0.
              – alfC
              2 hours ago










            • @alfC the wandbox example I link to shows it working w/o the endl.
              – Shafik Yaghmour
              2 hours ago











            • Ah, yes you are right. (I have a std::cout << std::endl somewhere else in the test code). It looks as if std::variant<> has an implicit contructor from anything?, maybe it is a bug in the implementation of std::variant?
              – alfC
              2 hours ago















            In my experiment, the code fails whether you have the std::endl or not. (and whether you have the "="). gcc 8.1/clang 6.0.
            – alfC
            2 hours ago




            In my experiment, the code fails whether you have the std::endl or not. (and whether you have the "="). gcc 8.1/clang 6.0.
            – alfC
            2 hours ago












            @alfC the wandbox example I link to shows it working w/o the endl.
            – Shafik Yaghmour
            2 hours ago





            @alfC the wandbox example I link to shows it working w/o the endl.
            – Shafik Yaghmour
            2 hours ago













            Ah, yes you are right. (I have a std::cout << std::endl somewhere else in the test code). It looks as if std::variant<> has an implicit contructor from anything?, maybe it is a bug in the implementation of std::variant?
            – alfC
            2 hours ago




            Ah, yes you are right. (I have a std::cout << std::endl somewhere else in the test code). It looks as if std::variant<> has an implicit contructor from anything?, maybe it is a bug in the implementation of std::variant?
            – alfC
            2 hours ago

















             

            draft saved


            draft discarded















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52845621%2fcant-stream-stdendl-with-overloaded-operator-for-stdvariant%23new-answer', 'question_page');

            );

            Post as a guest













































































            Comments

            Popular posts from this blog

            Long meetings (6-7 hours a day): Being “babysat” by supervisor

            Is the Concept of Multiple Fantasy Races Scientifically Flawed? [closed]

            Confectionery