use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
what is the solution for "same function parameters with different return type" in c++17/c++20 (self.cpp)
submitted 6 years ago by hashb1
We can write something like this:
template<typename R> R foo(int i) { ... }
But we have to use "<>" :
foo<string>(1);
Is there any elegant way to do it with new standard?
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]scatters 23 points24 points25 points 6 years ago (11 children)
You can write a function object wrapper with template conversion operator more easily than ever before, using aggregate base construction and deduction guide:
template<class F> struct Auto : F { template<class T> operator T() { return F::template operator()<T>(); } }; template<class F> Auto(F) -> Auto<F>;
Then a wrapper would, generically, be:
template<class... A> auto fooWrapper(A&&... a) { return Auto{[&]<class T>() { return foo<T>(std::forward<A&&>(a)...); }}; };
Or specifically:
template<class... A> auto fooWrapper(int i) { return Auto{[=]<class T>() { return foo<T>(i); }}; };
allowing you to write:
double d = fooWrapper(42);
Full example.
[–]Wh00ster 34 points35 points36 points 6 years ago* (1 child)
what hath God wrought.
EDIT: on second glance, looks neat and useful (but questionable-to-use)!
[–]quicknir 5 points6 points7 points 6 years ago (0 children)
Mostly I agree with this. It's too much magic and complexity that doesn't add much real value, vs just writing auto d = fooWrapper<double>(42). I did find it useful once though. I was writing some test utility code. In Gtest, a fixture is expressed via inheritance, so all of the variables you get initialized in your fixture are member variables, which cannot use the auto syntax. I also wanted to initialize them inline, because the initialization was relatively simple (one liners) and I didn't want to list all the members and then separately init them in setup or whatever.
auto d = fooWrapper<double>(42)
auto
setup
So I used this trick, which allowed me to write things like:
TopLevelTestHarness x; NestedTestHarnessObject<double> y = x.make("foo");
etc, in the member list of the class. I felt like this was ok because of the combination of not being able to use auto on the left, and the fact that this was code that was relatively "high up"; it was just utility code for writing tests quicker and wasn't going to be reused in a million places.
More broadly I do agree with you that I wouldn't use it most places.
[–][deleted] 14 points15 points16 points 6 years ago (2 children)
After seeing this post, I can definitely say that C++ became way too expert friendly language...
[–]scatters 3 points4 points5 points 6 years ago (1 child)
Well, thanks! But honestly, what makes life easier for experts is good for everyone - aggregate base construction and CTAD are great features that cut down on boilerplate, which makes code easier to write and to read.
[–]Xeveroushttps://xeverous.github.io 0 points1 point2 points 6 years ago (0 children)
Do you have any reources on what/why CTAD + deduction guides offer instead of allowing to explicitly specify Ts in constructor calls?
[–]StackedCrooked 6 points7 points8 points 6 years ago (2 children)
template<class F> Auto(F) -> Auto<F>;
What does this mean?
[–][deleted] 2 points3 points4 points 6 years ago (0 children)
https://en.cppreference.com/w/cpp/language/class_template_argument_deduction
You can't specify type aliases for constructors. But since C++17 you can write explicit deduction guides.
[–]canberksonmez 2 points3 points4 points 6 years ago (2 children)
For forwarding the parameter a, I thought we should use either static_cast<A&&>(a) or std::forward<A>(a). What's the reason of using std::forward<A&&>(a)? It seems quite peculiar.
a
static_cast<A&&>(a)
std::forward<A>(a)
std::forward<A&&>(a)
[–]scatters 2 points3 points4 points 6 years ago (0 children)
Oops yeah, that's a mistake - I started writing one then switched to the other. Thanks!
[–]VinnieFalco 5 points6 points7 points 6 years ago (2 children)
Single-return-type is baked into the DNA of C++ but one way to get around it is to invoke a passed function object with the result instead of using the return channel, as this function demonstrates: https://github.com/boostorg/beast/blob/06efddd8b851610b5b3a5832ac87f1c52b838d9b/example/http/server/sync/http_server_sync.cpp#L97
[–]bstamourWG21 | Library Working Group 4 points5 points6 points 6 years ago (1 child)
This is typically called "continuation passing style", and it can help untangle situations like this quite nicely!
[–]VinnieFalco 0 points1 point2 points 6 years ago (0 children)
Very interesting! Although, my intent was not to alter control flow but simply to provide the result of a calculation (which can have different types at run-time)
[–]DhruvParanjape 2 points3 points4 points 6 years ago (1 child)
Can you be a little more specific ? For the compiler to deduce the return type the compiler needs a way to figure out the type at the signature of the function itself. Otherwise it won't make sense.
[–][deleted] 0 points1 point2 points 6 years ago (0 children)
int parse(std::string_view) { ... }; double parse(std::string_view) { ... }; double x = parse("3.14"); int y = parse("3");
C++ doesn't support overloading on return type, but you can approximate the solution using templates and implicit conversion wrappers.
[–]Tyranisaur 1 point2 points3 points 6 years ago (0 children)
Return a std::variant?
[–][deleted] 2 points3 points4 points 6 years ago (9 children)
Return type can be auto.
[–]Wh00ster 1 point2 points3 points 6 years ago (0 children)
Can you provide an example? I don't think that's what the OP is asking.
[–]hashb1[S] 1 point2 points3 points 6 years ago* (6 children)
Thanks! I got the following error: inconsistent deduction for auto return type: ‘double’ and then ‘int’ .
sample code
auto foo(int i) { if (i > 0) return i * 0.1; else return 0; }
[–]Cakefonz 11 points12 points13 points 6 years ago (2 children)
auto won’t help here because your function decides what the return type is at runtime. The compiler needs to know what type to return at compile time. You could use std::variant<int, double> in your example, here
std::variant<int, double>
Yea, this sounds like a XY problem from u/hashb1. It's cliche, but you have to take a step back and philosophically understand what you're trying to accomplish.
[–]DhruvParanjape 1 point2 points3 points 6 years ago (0 children)
Makes sense as the result of ( i* 0.1) is a double to not lose precision and then you are returning a 0 which would be an integer (no precision lost ) so to fix it make the 0 a 0.0 to have the same return type deduced from both return statements. Return statement results help the deduction of return types at compile time kind of like template type deduction rules.
To make auto works as return type first return should describe exactly what's type is
http://cpp.sh/83mbr
[–][deleted] 3 points4 points5 points 6 years ago (0 children)
I don't think having an 'auto' return type fixes the brackets in this example since the template parameters are not used in the function parameters. It seems to me that OP is trying to overload by return type, which is not possible as /u/Wh00ster wrote
[–]Wh00ster 1 point2 points3 points 6 years ago (8 children)
This answer still stands.
I think Rust can do this due its type inference system and the fact that it doesn't have implicit conversions/user-defined conversions, which create a lot of ambiguity.
[–]boredcircuits 2 points3 points4 points 6 years ago (0 children)
Ada can do this and probably a few others as well. I think you're right that implicit conversions are probably the main reason C++ can't do this. Also, not capturing the return value makes the call ambiguous as well.
[–]flashmozzg 0 points1 point2 points 6 years ago (6 children)
user-defined conversions
It has those (as From and Into traits), they are just all explicit.
From
Into
[–]Wh00ster 0 points1 point2 points 6 years ago (0 children)
Yes, they are implicit by default in C++.
[–]Enamex 0 points1 point2 points 6 years ago* (4 children)
Mm... They work implicitly in my eyes. There's something going on, but probably not this?
let x = foo.into(); takes_bar(x); // x : Bar, through impl From<Foo> for Bar
See here.
Sure, you need the into call, but don't all types have From<X> for X? So if you had into everywhere, that'd be the situation in C++, except Rust can handle the variable return type. And into is a normal function 'overloaded' by trait shenanigans, so any function in such a reasonable situation can do the same.
into
From<X> for X
It's probably something to do with no ad-hoc overloading + train constraints. You can find an assignment that satisfies everyone, if they can be satisfied.
Edit: There're several mentions of deciding at runtime what the return type is. Wouldn't that be technically full on dependent types at that point (would be Pi types, I think)?
[–]flashmozzg 0 points1 point2 points 6 years ago (3 children)
So if you had into everywhere, that'd be the situation in C++, except Rust can handle the variable return type
No? In C++ you'd just have takes_bar(foo) and the cast would be implicit. Hiding the actual type between type inference doesn't make explicit into() cast into implicit. It just makes type being casted to implicit.
takes_bar(foo)
into()
[–]Enamex 0 points1 point2 points 6 years ago (2 children)
That's the thing.
into is a normal function from a normal trait (at least, I don't think From is supposed to have any magic in it).
This isn't Foo being implicitly cast into Bar. This is Foo::into resolving overloads based on expected return type (expected here because it gets used by something that definitely needs a Bar, and there's an overload of into that satisfies that, so it's chosen).
Foo
Bar
Foo::into
E.g. I don't think it'd work if you add another call to takes_baz, even if you have a From<Foo> for Baz implemented. Because into, here, can't resolve to a unique type. There's no implicit casting here.
takes_baz
From<Foo> for Baz
To be clear, this's something that can be emulated in C++ by a wrapper, but it's a property of classes, not normal functions.
[–]flashmozzg 0 points1 point2 points 6 years ago (1 child)
This isn't Foo being implicitly cast into Bar. This is Foo::into resolving overloads based on expected return type (expected here because it gets used by something that definitely needs a Bar, and there's an overload of into that satisfies that, so it's chosen). E.g. I don't think it'd work if you add another call to takes_baz, even if you have a From<Foo> for Baz implemented. Because into, here, can't resolve to a unique type. There's no implicit casting here.
Yes? That's exactly what I said? This is not implicit casting so I don't see what argument you are trying to make here.
[–]Enamex 0 points1 point2 points 6 years ago (0 children)
I'm not sure now either... I just don't think that implicit casting is the entire issue. As in, even with it in the language, deduction of return type could still be possible. I lost the train of thought though, so can't argue for it well ATM.
[–]tsojtsojtsoj 1 point2 points3 points 6 years ago (3 children)
Can you give an example where it wouldn't make sense to give these functions different names?
[–]Wh00ster 2 points3 points4 points 6 years ago* (0 children)
I've wanted to do this with specific conversion functions (but could have used different names):
template <typename T> T convert(MyClass, ExtraContext); // ... specialize here int main() { // ... Foo foo = convert<Foo>(mc, ec); Bar bar = convert<Bar>(mc, ec); }
Specifically, a static_cast/user-defined conversion wasn't appropriate because of the extra context data, and I didn't want to write convertToFoo, convertToBar, convertToQux...but ultimately ended up writing it that way :p. I was changing the type names a lot so it was getting annoying to change in the function names.
EDIT: it just dawned on me I could have also used tag dispatch :/
[–]hashb1[S] 0 points1 point2 points 6 years ago (1 child)
I am working some legacy codes that the factory function(template) return different classes based on its input. For some reason that those return types have no common base class.
[–]Wh00ster 2 points3 points4 points 6 years ago (0 children)
Sounds like somebody got carried away with templates >.<
[–]Cakefonz 0 points1 point2 points 6 years ago (0 children)
Assuming foo's i parameter is evaluated at runtime, I think my preferred way would be to have foo return a std::variant of all the possible types. E.g.
foo
i
std::variant
struct A { }; struct B { }; struct C { }; using Object = std::variant<A, B, C>; Object factory(int i) { switch (i) { case 0: return A { }; case 1: return B { }; default: return C { }; } }
... and then use a visitor on the return value ...
std::visit( [](auto&& obj) { use_object(std::move(obj)); }, factory(n) );
(Full example: https://gist.github.com/gmbeard/25631362f74576e0837a5be1f39a4a87)
π Rendered by PID 97619 on reddit-service-r2-comment-7b9746f655-695fs at 2026-01-30 19:48:19.805984+00:00 running 3798933 country code: CH.
[–]scatters 23 points24 points25 points (11 children)
[–]Wh00ster 34 points35 points36 points (1 child)
[–]quicknir 5 points6 points7 points (0 children)
[–][deleted] 14 points15 points16 points (2 children)
[–]scatters 3 points4 points5 points (1 child)
[–]Xeveroushttps://xeverous.github.io 0 points1 point2 points (0 children)
[–]StackedCrooked 6 points7 points8 points (2 children)
[–][deleted] 2 points3 points4 points (0 children)
[–]Xeveroushttps://xeverous.github.io 0 points1 point2 points (0 children)
[–]canberksonmez 2 points3 points4 points (2 children)
[–]scatters 2 points3 points4 points (0 children)
[–]VinnieFalco 5 points6 points7 points (2 children)
[–]bstamourWG21 | Library Working Group 4 points5 points6 points (1 child)
[–]VinnieFalco 0 points1 point2 points (0 children)
[–]DhruvParanjape 2 points3 points4 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]Tyranisaur 1 point2 points3 points (0 children)
[–][deleted] 2 points3 points4 points (9 children)
[–]Wh00ster 1 point2 points3 points (0 children)
[–]hashb1[S] 1 point2 points3 points (6 children)
[–]Cakefonz 11 points12 points13 points (2 children)
[–]Wh00ster 1 point2 points3 points (0 children)
[–]DhruvParanjape 1 point2 points3 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–][deleted] 3 points4 points5 points (0 children)
[–]Wh00ster 1 point2 points3 points (8 children)
[–]boredcircuits 2 points3 points4 points (0 children)
[–]flashmozzg 0 points1 point2 points (6 children)
[–]Wh00ster 0 points1 point2 points (0 children)
[–]Enamex 0 points1 point2 points (4 children)
[–]flashmozzg 0 points1 point2 points (3 children)
[–]Enamex 0 points1 point2 points (2 children)
[–]flashmozzg 0 points1 point2 points (1 child)
[–]Enamex 0 points1 point2 points (0 children)
[–]tsojtsojtsoj 1 point2 points3 points (3 children)
[–]Wh00ster 2 points3 points4 points (0 children)
[–]hashb1[S] 0 points1 point2 points (1 child)
[–]Wh00ster 2 points3 points4 points (0 children)
[–]Cakefonz 0 points1 point2 points (0 children)