I have a simple traits function:
template <typename Traits>
struct Cal {
typedef typename Traits::T T;
static T f(T a, T b);
};
struct FTraits {
typedef float T;
};
struct DTraits {
typedef double T;
};
I can think of 4 ways to implement Cal::f and specify the return type.
// option 1. compile. as inline implementation
template <typename Traits>
struct Cal {
typedef typename Traits::T T;
static T f(T a, T b) {
return a+b;
}
};
// option 2. compile
template <typename Traits>
typename Traits::T Cal<Traits>::f(T a, T b) {
return a+b;
};
// option 3. does not compile
template <typename Traits>
T Cal<Traits>::f(T a, T b) {
return a+b;
};
// option 4. compile
template <typename Traits>
auto Cal<Traits>::f(T a, T b) -> T {
return a+b;
};
I believe option 4 is added in c++11 as option 3 is not possible in the previous standard. My question is, why option 3 does not work? Specifically, I wonder the reason behind that return type T cannot name a type, whereas argument type T can name a type. Does compiler work in different contexts for return and argument types? Also, why c++11 choose option 4 over option 3? It seems option 3 is more intuitive than option 4.
Even compilers of a sophisticated language like C++ still need to process the file from the beginning to the end.
If the declaration after template< … > begins with T, the compiler needs to know what T is, in order to parse it and determine that it's a return type, before proceeding to find the rest of the declaration.
Essentially, the qualifier Cal< Traits >:: needs to come syntactically before any unqualified uses of members of Cal. It's much easier to extend the language with trailing return types, which place Cal< Traits >:: immediately after auto, than to create a heuristic for skipping over type names with unknown identifiers.
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