ostream for X, then generate for optional, unique_ptr, shared_ptr, possibly variant or vector










-1















Given a type X which should be printed I naturally implement
std::ostream& operator<<(std::ostream& os, const X& x);



If I want to avoid repeating the work for various wrappers like std::optional<X>, std::unique_ptr<X>, std::shared_ptr<X> etc. what are my options? Are there libraries which implement this already? Given these keywords something like this is terribly hard to search for, the closed I could find was the Compile Time Type Information library, something I'd probably use to enhance the optional and vector outputs, but I want to avoid reinventing the wheel.










share|improve this question






















  • All the types you mentioned would need a different operator<<, since they might not have a value (you'd want to print something different/nothing for empty smart pointers and optionals).

    – Pezo
    Nov 13 '18 at 18:30











  • Yes, they would check for "empty", then just output "" or otherwise dereference the value and call the implemented operator and maybe add "uqX" - but that logic only needs to be written once for each wrapping type.

    – finite graygreen
    Nov 13 '18 at 18:37
















-1















Given a type X which should be printed I naturally implement
std::ostream& operator<<(std::ostream& os, const X& x);



If I want to avoid repeating the work for various wrappers like std::optional<X>, std::unique_ptr<X>, std::shared_ptr<X> etc. what are my options? Are there libraries which implement this already? Given these keywords something like this is terribly hard to search for, the closed I could find was the Compile Time Type Information library, something I'd probably use to enhance the optional and vector outputs, but I want to avoid reinventing the wheel.










share|improve this question






















  • All the types you mentioned would need a different operator<<, since they might not have a value (you'd want to print something different/nothing for empty smart pointers and optionals).

    – Pezo
    Nov 13 '18 at 18:30











  • Yes, they would check for "empty", then just output "" or otherwise dereference the value and call the implemented operator and maybe add "uqX" - but that logic only needs to be written once for each wrapping type.

    – finite graygreen
    Nov 13 '18 at 18:37














-1












-1








-1








Given a type X which should be printed I naturally implement
std::ostream& operator<<(std::ostream& os, const X& x);



If I want to avoid repeating the work for various wrappers like std::optional<X>, std::unique_ptr<X>, std::shared_ptr<X> etc. what are my options? Are there libraries which implement this already? Given these keywords something like this is terribly hard to search for, the closed I could find was the Compile Time Type Information library, something I'd probably use to enhance the optional and vector outputs, but I want to avoid reinventing the wheel.










share|improve this question














Given a type X which should be printed I naturally implement
std::ostream& operator<<(std::ostream& os, const X& x);



If I want to avoid repeating the work for various wrappers like std::optional<X>, std::unique_ptr<X>, std::shared_ptr<X> etc. what are my options? Are there libraries which implement this already? Given these keywords something like this is terribly hard to search for, the closed I could find was the Compile Time Type Information library, something I'd probably use to enhance the optional and vector outputs, but I want to avoid reinventing the wheel.







c++ iostream






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 13 '18 at 18:14









finite graygreenfinite graygreen

27618




27618












  • All the types you mentioned would need a different operator<<, since they might not have a value (you'd want to print something different/nothing for empty smart pointers and optionals).

    – Pezo
    Nov 13 '18 at 18:30











  • Yes, they would check for "empty", then just output "" or otherwise dereference the value and call the implemented operator and maybe add "uqX" - but that logic only needs to be written once for each wrapping type.

    – finite graygreen
    Nov 13 '18 at 18:37


















  • All the types you mentioned would need a different operator<<, since they might not have a value (you'd want to print something different/nothing for empty smart pointers and optionals).

    – Pezo
    Nov 13 '18 at 18:30











  • Yes, they would check for "empty", then just output "" or otherwise dereference the value and call the implemented operator and maybe add "uqX" - but that logic only needs to be written once for each wrapping type.

    – finite graygreen
    Nov 13 '18 at 18:37

















All the types you mentioned would need a different operator<<, since they might not have a value (you'd want to print something different/nothing for empty smart pointers and optionals).

– Pezo
Nov 13 '18 at 18:30





All the types you mentioned would need a different operator<<, since they might not have a value (you'd want to print something different/nothing for empty smart pointers and optionals).

– Pezo
Nov 13 '18 at 18:30













Yes, they would check for "empty", then just output "" or otherwise dereference the value and call the implemented operator and maybe add "uqX" - but that logic only needs to be written once for each wrapping type.

– finite graygreen
Nov 13 '18 at 18:37






Yes, they would check for "empty", then just output "" or otherwise dereference the value and call the implemented operator and maybe add "uqX" - but that logic only needs to be written once for each wrapping type.

– finite graygreen
Nov 13 '18 at 18:37













1 Answer
1






active

oldest

votes


















1














So, the basic idea is that you add a templated operator<< that would SFINAE away based on the return type of operator* of the object it gets passed. Something like this:



template <typename T, typename Expected>
using deref_to = std::is_same<std::decay_t<decltype(*std::declval<T>())>, Expected>;

template <typename T, typename = std::enable_if_t<deref_to<T, X>::value>>
std::ostream& operator<<(std::ostream &os, const T &foo)
if(!foo)
os << "";
else
os << *foo;
return os;



Live demo, this even works for raw pointers. Doesn't cover variant or vector, although that shouldn't be too difficult to add as well.



To handle std::variant, std::tuple, and std::pair you would probably do the same, just with std::get<X> instead of operator*.






share|improve this answer

























  • Though that exactly does not compile (X/Expected is undefined), I now use the explicit specializations (Filler because otherwise the templates are seen as duplicates)...

    – finite graygreen
    Nov 14 '18 at 17:06











  • template <typename T, typename U = std::remove_reference_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::unique_ptr<U>> >, typename Filler1 = char>

    – finite graygreen
    Nov 14 '18 at 17:07












  • template <typename T, typename O = std::decay_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::optional<O>>>, typename Filler1 = char, typename Filler2 = char>

    – finite graygreen
    Nov 14 '18 at 17:07











  • Look at the live demo, modulo copy paste errors it compiles exactly as posted. What error do you get?

    – Pezo
    Nov 14 '18 at 17:16











  • Just tested whether the operator<< template is too greedy, doesn't seem like it.

    – Pezo
    Nov 14 '18 at 18:27










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',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
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%2f53287184%2fostream-for-x-then-generate-for-optionalx-unique-ptrx-shared-ptrx-poss%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














So, the basic idea is that you add a templated operator<< that would SFINAE away based on the return type of operator* of the object it gets passed. Something like this:



template <typename T, typename Expected>
using deref_to = std::is_same<std::decay_t<decltype(*std::declval<T>())>, Expected>;

template <typename T, typename = std::enable_if_t<deref_to<T, X>::value>>
std::ostream& operator<<(std::ostream &os, const T &foo)
if(!foo)
os << "";
else
os << *foo;
return os;



Live demo, this even works for raw pointers. Doesn't cover variant or vector, although that shouldn't be too difficult to add as well.



To handle std::variant, std::tuple, and std::pair you would probably do the same, just with std::get<X> instead of operator*.






share|improve this answer

























  • Though that exactly does not compile (X/Expected is undefined), I now use the explicit specializations (Filler because otherwise the templates are seen as duplicates)...

    – finite graygreen
    Nov 14 '18 at 17:06











  • template <typename T, typename U = std::remove_reference_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::unique_ptr<U>> >, typename Filler1 = char>

    – finite graygreen
    Nov 14 '18 at 17:07












  • template <typename T, typename O = std::decay_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::optional<O>>>, typename Filler1 = char, typename Filler2 = char>

    – finite graygreen
    Nov 14 '18 at 17:07











  • Look at the live demo, modulo copy paste errors it compiles exactly as posted. What error do you get?

    – Pezo
    Nov 14 '18 at 17:16











  • Just tested whether the operator<< template is too greedy, doesn't seem like it.

    – Pezo
    Nov 14 '18 at 18:27















1














So, the basic idea is that you add a templated operator<< that would SFINAE away based on the return type of operator* of the object it gets passed. Something like this:



template <typename T, typename Expected>
using deref_to = std::is_same<std::decay_t<decltype(*std::declval<T>())>, Expected>;

template <typename T, typename = std::enable_if_t<deref_to<T, X>::value>>
std::ostream& operator<<(std::ostream &os, const T &foo)
if(!foo)
os << "";
else
os << *foo;
return os;



Live demo, this even works for raw pointers. Doesn't cover variant or vector, although that shouldn't be too difficult to add as well.



To handle std::variant, std::tuple, and std::pair you would probably do the same, just with std::get<X> instead of operator*.






share|improve this answer

























  • Though that exactly does not compile (X/Expected is undefined), I now use the explicit specializations (Filler because otherwise the templates are seen as duplicates)...

    – finite graygreen
    Nov 14 '18 at 17:06











  • template <typename T, typename U = std::remove_reference_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::unique_ptr<U>> >, typename Filler1 = char>

    – finite graygreen
    Nov 14 '18 at 17:07












  • template <typename T, typename O = std::decay_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::optional<O>>>, typename Filler1 = char, typename Filler2 = char>

    – finite graygreen
    Nov 14 '18 at 17:07











  • Look at the live demo, modulo copy paste errors it compiles exactly as posted. What error do you get?

    – Pezo
    Nov 14 '18 at 17:16











  • Just tested whether the operator<< template is too greedy, doesn't seem like it.

    – Pezo
    Nov 14 '18 at 18:27













1












1








1







So, the basic idea is that you add a templated operator<< that would SFINAE away based on the return type of operator* of the object it gets passed. Something like this:



template <typename T, typename Expected>
using deref_to = std::is_same<std::decay_t<decltype(*std::declval<T>())>, Expected>;

template <typename T, typename = std::enable_if_t<deref_to<T, X>::value>>
std::ostream& operator<<(std::ostream &os, const T &foo)
if(!foo)
os << "";
else
os << *foo;
return os;



Live demo, this even works for raw pointers. Doesn't cover variant or vector, although that shouldn't be too difficult to add as well.



To handle std::variant, std::tuple, and std::pair you would probably do the same, just with std::get<X> instead of operator*.






share|improve this answer















So, the basic idea is that you add a templated operator<< that would SFINAE away based on the return type of operator* of the object it gets passed. Something like this:



template <typename T, typename Expected>
using deref_to = std::is_same<std::decay_t<decltype(*std::declval<T>())>, Expected>;

template <typename T, typename = std::enable_if_t<deref_to<T, X>::value>>
std::ostream& operator<<(std::ostream &os, const T &foo)
if(!foo)
os << "";
else
os << *foo;
return os;



Live demo, this even works for raw pointers. Doesn't cover variant or vector, although that shouldn't be too difficult to add as well.



To handle std::variant, std::tuple, and std::pair you would probably do the same, just with std::get<X> instead of operator*.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 13 '18 at 18:58

























answered Nov 13 '18 at 18:51









PezoPezo

969512




969512












  • Though that exactly does not compile (X/Expected is undefined), I now use the explicit specializations (Filler because otherwise the templates are seen as duplicates)...

    – finite graygreen
    Nov 14 '18 at 17:06











  • template <typename T, typename U = std::remove_reference_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::unique_ptr<U>> >, typename Filler1 = char>

    – finite graygreen
    Nov 14 '18 at 17:07












  • template <typename T, typename O = std::decay_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::optional<O>>>, typename Filler1 = char, typename Filler2 = char>

    – finite graygreen
    Nov 14 '18 at 17:07











  • Look at the live demo, modulo copy paste errors it compiles exactly as posted. What error do you get?

    – Pezo
    Nov 14 '18 at 17:16











  • Just tested whether the operator<< template is too greedy, doesn't seem like it.

    – Pezo
    Nov 14 '18 at 18:27

















  • Though that exactly does not compile (X/Expected is undefined), I now use the explicit specializations (Filler because otherwise the templates are seen as duplicates)...

    – finite graygreen
    Nov 14 '18 at 17:06











  • template <typename T, typename U = std::remove_reference_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::unique_ptr<U>> >, typename Filler1 = char>

    – finite graygreen
    Nov 14 '18 at 17:07












  • template <typename T, typename O = std::decay_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::optional<O>>>, typename Filler1 = char, typename Filler2 = char>

    – finite graygreen
    Nov 14 '18 at 17:07











  • Look at the live demo, modulo copy paste errors it compiles exactly as posted. What error do you get?

    – Pezo
    Nov 14 '18 at 17:16











  • Just tested whether the operator<< template is too greedy, doesn't seem like it.

    – Pezo
    Nov 14 '18 at 18:27
















Though that exactly does not compile (X/Expected is undefined), I now use the explicit specializations (Filler because otherwise the templates are seen as duplicates)...

– finite graygreen
Nov 14 '18 at 17:06





Though that exactly does not compile (X/Expected is undefined), I now use the explicit specializations (Filler because otherwise the templates are seen as duplicates)...

– finite graygreen
Nov 14 '18 at 17:06













template <typename T, typename U = std::remove_reference_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::unique_ptr<U>> >, typename Filler1 = char>

– finite graygreen
Nov 14 '18 at 17:07






template <typename T, typename U = std::remove_reference_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::unique_ptr<U>> >, typename Filler1 = char>

– finite graygreen
Nov 14 '18 at 17:07














template <typename T, typename O = std::decay_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::optional<O>>>, typename Filler1 = char, typename Filler2 = char>

– finite graygreen
Nov 14 '18 at 17:07





template <typename T, typename O = std::decay_t<decltype(*std::declval<T>())>, typename = std::enable_if_t< std::is_same_v<T, std::optional<O>>>, typename Filler1 = char, typename Filler2 = char>

– finite graygreen
Nov 14 '18 at 17:07













Look at the live demo, modulo copy paste errors it compiles exactly as posted. What error do you get?

– Pezo
Nov 14 '18 at 17:16





Look at the live demo, modulo copy paste errors it compiles exactly as posted. What error do you get?

– Pezo
Nov 14 '18 at 17:16













Just tested whether the operator<< template is too greedy, doesn't seem like it.

– Pezo
Nov 14 '18 at 18:27





Just tested whether the operator<< template is too greedy, doesn't seem like it.

– Pezo
Nov 14 '18 at 18:27

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53287184%2fostream-for-x-then-generate-for-optionalx-unique-ptrx-shared-ptrx-poss%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







這個網誌中的熱門文章

What does pagestruct do in Eviews?

Dutch intervention in Lombok and Karangasem

Channel Islands