Omit return type in C++11
Solution 1
It would appear that g++ 4.8 is getting an implementation of auto return type deduction. The patch was put in by Jason Merrill who is also sending a paper for C++-1Y for the feature. The feature is available with -std=c++1y.
Still playing with it.
Solution 2
The rationale for this behavior is given in the draft, 8.3.5p12:
A trailing-return-type is most useful for a type that would be more complicated to specify before the declarator-id:
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
rather than
template <class T, class U> decltype((*(T*)0) + (*(U*)0)) add(T t, U u);
So this is really only meant to simplify the case where referring to the parameter names helps.
If you assume that C++ could always infer the return type of functions from the function body: this is not going to fly. It's a goal of C++ (and C) to allow modularity by separating declaration from implementation, so at the point of the call, you may not have the body of the function available. However, every caller needs to know the parameter types and the return type of every function/method being called.
Solution 3
If you are simply trying to set the return type, make it a template argument. This way you can change everything related to the return type without actually changing the function. You can put a default return type if you want like in this example.
template <class R = int, class T>
R f(T&& x)
{
...
return h2(y2, y3);
}
The code below demonstrates it's effectiveness.
DEMO CODE:
#include <iostream>
#include <iomanip>
template <class T, class S>
T h2(T& x, S& y)
{
return x + y;
}
template <class R = int, class T>
R f(T& x)
{
auto y2 = x;
auto y3 = x;
return h2(y2, y3);
}
int main(int argc, char** argv)
{
int x = 7;
std::string str = "test! ";
auto d = f<double>(x);
auto i = f(x); // use default type (int)
auto s = f<std::string>(str);
std::cout << std::fixed << std::setprecision(4);
std::cout << "double: " << d << std::endl;
std::cout << "int: " << i << std::endl;
std::cout << "string: " << s << std::endl;
return 0;
}
OUTPUT:
double: 14.0000
int: 14
string: test! test!
Unfortunately, the exact functionality you are looking for does not exist (yet) and is not part of the C++0x spec. However, it is possible this may be part of the C++1x spec when it is drafted. until then, stick to templates.
Solution 4
EDIT: oops, I just realized that there's a scoping difference between the trailing-return-type specifier and the return statement. Specifically:
auto f(int a)
{
char r[sizeof(f(a))+1];
return r;
}
Kaboom!
Previous answer:
It's unfortunate that the language does not provide a syntax to have the compiler infer the return type in this case, because it's trivial to show that inference is possible.
Specifically, we are talking about the case where there is exactly one return statement inside the function.
Independent of where in the function that return statement is, or how complex the preceding code is, it should be clear that the following transformation is possible:
return (ugly expression);
into
auto return_value = (ugly expression);
return return_value;
If the compiler can infer the type of return_value
(and according to the C++0x rules, it can), then the inferred type of return_value
can be chosen as the return type of the function.
It therefore seems to me that a modification to C++0x where the trailing return type specifier should only be required when the multiplicity of return statements is not exactly one would be feasible and solve the problem.
Solution 5
I agree with Yttrill. Return type deduction has already been proved to be a feasible practice in languages like Haskell, and since C++ has already achieved 'auto', it is just one step further to achieve return type deduction. This deduction should happens at the time of specialization, not template definition, since information of the real type supplied to the template is needed. The separate of declaration and definition is no longer a common practice in generic C++, because template body must be written in header files, and hence template bodies almost always go with template declarations. In situations where there are multiple return statements and types of them do not match, the compiler can happily report en error. In summary, return type deduction is totally possible in C++, if the committee wants to. And it's VERY important, because the duplication of manually writing return types hinders the pervasive use of small generic helper functions, which is such a common practice in functional and generic programming.
Clinton
Updated on July 05, 2022Comments
-
Clinton almost 2 years
I've recently found myself using the following macro with gcc 4.5 in C++11 mode:
#define RETURN(x) -> decltype(x) { return x; }
And writing functions like this:
template <class T> auto f(T&& x) RETURN (( g(h(std::forward<T>(x))) ))
I've been doing this to avoid the inconvenience having to effectively write the function body twice, and having keep changes in the body and the return type in sync (which in my opinion is a disaster waiting to happen).
The problem is that this technique only works on one line functions. So when I have something like this (convoluted example):
template <class T> auto f(T&& x) -> ... { auto y1 = f(x); auto y2 = h(y1, g1(x)); auto y3 = h(y1, g2(x)); if (y1) { ++y3; } return h2(y2, y3); }
Then I have to put something horrible in the return type.
Furthermore, whenever I update the function, I'll need to change the return type, and if I don't change it correctly, I'll get a compile error if I'm lucky, or a runtime bug in the worse case. Having to copy and paste changes to two locations and keep them in sync I feel is not good practice.
And I can't think of a situation where I'd want an implicit cast on return instead of an explicit cast.
Surely there is a way to ask the compiler to deduce this information. What is the point of the compiler keeping it a secret? I thought C++11 was designed so such duplication would not be required.
-
SoapBox over 13 yearsMaybe you need to reconsider the code you're writing if you have so many functions using decltype. We survived a long time without decltype at all...
-
GManNickG over 13 years(You make it sound like you're changing the function every other hour.) Yes, it would be nice if the compiler could deduce the return type automatically, but it simply isn't there, and there's a point where you have to stop trying to be the compiler and just write code it accepts. (And yes, C++0x alleviates many things, but it can't, unfortunately, go all out.) So just specify the return type.
-
Clinton over 13 yearsI don't think all the negative comments are reasonable. Boost libraries are full of function objects with things like ::return_type to work around these sort of issues. Do you really think that having to define a new class just to define the return type of your function is 'readable'?! I don't see what is so unreadable about not having to replicate the same information in three different ways.
-
Yakov Galka over 13 years@Clinton: I think that if you can't easily reason about what's the return type of your function, then your design is wrong.
-
Clinton over 13 years@ybungalobill: Can you easily reason about the return type of boost fusion vectors? If not, do you think their design is wrong? And if so, how would you do it?
-
Yakov Galka over 13 years@Clinton: I don't understand your question, boost fusion vectors don't have an invocation operator, so what return type??..
-
Puppy over 13 yearsThere's a reason that decltype and the lazy return type syntax was introduced, and that's because it's impossible or unbelievably hard to determine the type of many functions involving forwarding beforehand. @SoapBox: I disagree wholeheartedly in a respectful manner.
-
Faisal Vali over 12 years@Clinton - This is a very reasonable request especially since lambda return types are deduceable in certain situations - I believe deduceable return types for all functions in similar situations is still being pondered by the standard's committee. It would certainly help if a compiler implemented such an extension successfully first.
-
alfC about 11 yearsIt has some limitations but this can be useful cpp-next.com/archive/2011/11/having-it-all-pythy-syntax and github.com/pfultz2/Pythy
-
cheshirekow over 10 years@LokiAstari I agree with your comment in the context of the OP but what if a function returns the result of
std::bind(...)
? -
Martin York over 10 years@cheshirekow: That is the perfect place (with std::bind) to use
auto
. Withstd::bind
you don't actually care about the actual underlying type; just that it will perform the actions you want.
-
-
Clinton over 13 yearsthe return type would be something like decltype(h2(h(f(x),g1(x),h(f(x),g2(x))). I could write it explicitly, but it is messy repetition.
-
user253751 over 13 yearsbecause you can't figure out the type ahead of time? eg: if h2 returns an X, set it to X
-
Puppy over 13 yearsWith rvalue references, that's often not possible. The entire reason this syntax was devised is because it's not possible to know the return type ahead of time.
-
user253751 over 13 yearsbut... why are you changing the return type every time you edit the function? "Furthermore, whenever I update the function, I'll need to change the return type"
-
Clinton over 13 yearsYttrill: Could you elaborate on this? Would "template class<T> decltype(a.f()) f(T a) { return a.f(); } fail? (which is what my macro does)
-
Martin v. Löwis over 13 yearswhat you are missing that "auto" for return types means that you need to use the trailing-return-type declaration (-> T).
-
Ben Voigt over 13 yearsNo, you can't figure out the type ahead of time. It depends on
T
. Remember thatg1()
,g2()
,h()
, andh2()
can all be template functions and can be specialized. Adding a new specialization to any of those other functions could change the return type off()
and would do so without any modifications tof()
itself -
Alex B about 13 yearsIf you have multiple return statements with different types, you need to find a superset of all types specified. I think this feature will be needlessly complicated and result in a lot of cryptic errors and corner cases: (e.g. you return pointers
A*
andB*
to forward declared classes, which are actually derive from on another, if only forward declarations are available, deduction will fail). -
Yoav over 11 yearsFor many years people even did have C++! Why do we need C++, you can always use C, or even assembly. Code duplication is known as the best programming practice ever!
-
Charphacy about 11 yearsBut you can write
auto f = [&](int a) { char r[sizeof(f(a))+1]; return r; };
, and compilers just give you an error if you do, e.g., “error: variable 'f' declared with 'auto' type cannot appear in its own initializer” -
emsr about 11 yearsReturn type deduction has been voted into C++14. The latest paper has the details.
-
EFraim over 10 yearsTemplate bodies do not really have to be written in header files: you can write the body in .cpp .cxx as usual and have it explicitly instantiated for instances that you can use. This does not work for all use-cases, but it often does help reduce compilation time and improve readability.
-
j_kubik over 9 years(-1) Independent of your reasoning, it is rather clear that OP knew about this possibility, and it doesn't solve his problem. And as for your question - "Does your return type really change that often?" - well, if it is just some helper inline function (for which
auto
is mostly useful for) it will be necessary to get return type exactly as result of the expression producing it. If it differs, compiler will be forced to do additional type conversion even in inlined code, which is usually not what we want - and even if it doesn't actually lose data, it is suboptimal performance-wise. -
kirbyfan64sos about 9 yearsIn C++14, this is possible.