I have the following code:
#include <iostream>
struct C {
int a;
int& get() { return a; }
};
struct D {
int a;
int get() { return a; }
};
template <typename T>
auto foo(T o) { // no sample code is complete without a foo
return o.get();
}
int main()
{
C c;
D d;
c.a = 2;
d.a = 42; // no sample code is complete without a 42
std::cout << "c=" << c.a << ", d=" << d.a << "\n";
c.get() = 3;
//d.get() = 43;
std::cout << "c=" << c.a << ", d=" << d.a << "\n";
foo(c) = 4; // <--- why won't this work?
//foo(d) = 44;
std::cout << "c=" << c.a << ", d=" << d.a << "\n";
}
Why won't the line marked compile? It seems that the copiler is deducing the return type of foo<C>
to be int
instead of the int&
I would expect. Why is this and how can I get it to deduce the reference, too?
http://coliru.stacked-crooked.com/a/6ab909680836fd24
In C++14, you can just use auto as a return type.
The auto keyword by itself represents a value type, similar to int or char . It can be modified with the const keyword and the & symbol to represent a const type or a reference type, respectively.
If you use the automatic return type deduction instead (with or without decltype(auto)), you won't get expression SFINAE and calling foobaron an instance of either Xor Ywill trigger a compile-time error. Share Follow edited May 13 2016 at 8:38 answered Apr 8 2013 at 14:44 MorwennMorwenn
auto in a function return type or a lambda parameter implies template type deduction, not auto type deduction. Item 3: Understand decltype. decltype is an odd creature. Given a name or an expression, decltype tells you the name’s or the expression’s type. Typically, what it tells you is exactly what you’d predict.
As a very light example: template<typename T, typename U> auto add(T t, U u) { //almost deduced as decltype(t + u): decltype(auto) would return t + u; } I don't believe that would ever really be a problem, though I guess having the return type explicitly depend on the parameters could be clearer in some cases. Scenario 3
C++14 permits auto to indicate that a function’s return type should be deduced (see Item 3 ), and C++14 lambdas may use auto in parameter declarations. However, these uses of auto employ template type deduction, not auto type deduction. So a function with an auto return type that returns a braced initializer won’t compile:
Given auto
, which is declared as a non-reference, so we're dealing with pass-by-value case. And auto
follows the rules of template argument deduction; the reference part of int&
will be ignored, then the deduced type is int
.
You can use decltype(auto)
(since C++14) instead.
type is
decltype(e)
, wheree
is the initializer.
template <typename T>
decltype(auto) foo(T&& o) { // no sample code is complete without a foo
return o.get();
}
The return type is deduced as decltype(o.get())
, and according to the rule of decltype
,
if the value category of expression is lvalue, then decltype yields
T&
;
c.get()
returns int&
, which is an lvalue, then we get the return type int&
insteand of int
.
BTW: Note that if o
is still passed by-value, the returned reference would be dangled.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With