I was playing around with an adapter for using range-based for-loops to iterate in reverse. (I did not know about the boost adapter ("adaptor") for that purpose. I am a big believer in not re-inventing the wheel if it's a free wheel I have already downloaded.)
What puzzles me is why VC++ 2012 is not happy unless I use trailing return-types in the code that follows:
#include <string>
#include <iostream>
template<class Fwd>
struct Reverser {
const Fwd &fwd;
Reverser<Fwd>(const Fwd &fwd_): fwd(fwd_) {}
auto begin() -> decltype(fwd.rbegin()) const { return fwd.rbegin(); }
auto end() -> decltype(fwd.rend()) const { return fwd.rend(); }
};
template<class Fwd>
Reverser<Fwd> reverse(const Fwd &fwd) { return Reverser<Fwd>(fwd); }
int main() {
using namespace std;
const string str = ".dlrow olleH";
for(char c: reverse(str)) cout << c;
cout << endl;
}
When I tried the following, I got the errors, "error C2100: illegal indirection," and "error C2228: left of '.rbegin' must have class/struct/union". What am I missing?
template<class Fwd>
struct Reverser {
const Fwd &fwd;
Reverser<Fwd>(const Fwd &fwd_): fwd(fwd_) {}
decltype(fwd.rbegin()) begin() const { return fwd.rbegin(); }
decltype(fwd.rend()) end() const { return fwd.rend(); }
};
UPDATE: In light of the discussion about a "this" pointer, I tried another tack. Look Ma, no this! And it compiles fine. I do believe that, rightly or wrongly, VC++ is not aware of that this.
template<class Fwd>
struct Reverser {
const Fwd &fwd;
Reverser<Fwd>(const Fwd &fwd_): fwd(fwd_) {}
decltype(((const Fwd*)0)->rbegin()) begin() const { return fwd.rbegin(); }
decltype(((const Fwd*)0)->rend()) end() const { return fwd.rend(); }
};
UPDATE 2: Submitted to MS: https://connect.microsoft.com/VisualStudio/feedback/details/765455/vc-2012-compiler-refuses-decltype-return-spec-for-member-function
UPDATE 3: This problem is fixed as of VC++ 2015. Thanks, Microsoft person.
Every method in Java is declared with a return type and it is mandatory for all java methods. A return type may be a primitive type like int, float, double, a reference type or void type(returns nothing). The type of data returned by a method must be compatible with the return type specified by the method.
In C++14, you can just use auto as a return type.
Some functions perform the desired operations without returning a value. In this case, the return_type is the keyword void. Function Name − This is the actual name of the function. The function name and the parameter list together constitute the function signature. Parameters − A parameter is like a placeholder.
NOTE FROM OP: VC++ was buggy. VC++ 2015 accepts the code correctly.
My original answer that the code that VC++ rejected is disallowed in the standard actually was wrong: It is allowed as Johannes Schaub pointed out: in 5.1 [expr.prim.general] paragraph 12 it is described where an id-expression denoting a non-static data member or a non-static member function can be used. In particular, the last bullet states:
if that id-expression denotes a non-static data member and it appears in an unevaluated operand.
The expression in decltype(expr)
is an unevaluated operand. Furthermore, 9.3.1 [class.mfct.non-static] paragraph 3 explains the situation where this
is implicitly added to an expression:
When an id-expression (5.1) that is not part of a class member access syntax (5.2.5) and not used to form a pointer to member (5.3.1) is used in a member of class X in a context where this can be used (5.1.1), if name lookup (3.4) resolves the name in the id-expression to a non-static non-type member of some class C, and if either the id-expression is potentially evaluated or C is X or a base class of X, the id-expression is transformed into a class member access expression (5.2.5) using (*this) (9.3.2) as the postfix-expression to the left of the . operator.
The context in question is not "potentially evaluated" and there is no based involved. Thus, this
isn't added and doesn't have to be in scope. Taken together, this means that the declaration
decltype(fwd.rbegin()) begin() const;
should be legal. It seems that using
decltype(static_cast<Reverser<Fwd> const*>(0)->fwd.rbegin()) begin() const;
is a work-around in cases where the compiler isn't correctly implemented.
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