template <class T>
struct foo {
int x;
decltype(x) f1();
};
It seems to be impossible to define f1
out-of-line. I have tried the following definitions, and none of them work:
template <class T> decltype(x) foo<T>::f1() {}
template <class T> auto foo<T>::f1() -> decltype(x) {}
template <class T> auto foo<T>::f1() { return x; }
template <class T> decltype(std::declval<foo<T>>().x) foo<T>::f1() {}
// This return type is copied from the gcc error message
template <class T> decltype (((foo<T>*)(void)0)->foo<T>::x) foo<T>::f1() {}
This isn't a problem in real code because changing the in-class declaration of f1
to auto f1() -> decltype(x);
allows the second definition. but I'm puzzled as to why that changes anything. Is it even possible to declare the original f1
out-of-line?
Member functions of class templates (C++ only) You may define a template member function outside of its class template definition. The overloaded addition operator has been defined outside of class X . The statement a + 'z' is equivalent to a. operator+('z') .
If the expression parameter is a call to a function or an overloaded operator function, decltype(expression) is the return type of the function. Parentheses around an overloaded operator are ignored. If the expression parameter is an rvalue, decltype(expression) is the type of expression .
A non-template class can have template member functions, if required. Notice the syntax. Unlike a member function for a template class, a template member function is just like a free template function but scoped to its containing class.
To define a member function outside the class definition we have to use the scope resolution :: operator along with class name and function name.
As dumb as this might seem, I believe the following is correct:
template <class T>
struct foo {
int x;
decltype(x) f1();
};
template <class T>
int foo<T>::f1() { return 0; }
Clang accepts it, but GCC doesn't, so I am going to say that I think GCC has a bug. [Coliru link]
The issue is whether these two declarations of f1
declare the same function (more technically, the same member function of the same class template). This is governed by [basic.link]/9, according to which:
Two names that are the same (Clause 6) and that are declared in different scopes shall denote the same variable, function, type, template or namespace if
- both names have external linkage or else both names have internal linkage and are declared in the same translation unit; and
- both names refer to members of the same namespace or to members, not by inheritance, of the same class; and
- when both names denote functions, the parameter-type-lists of the functions (11.3.5) are identical; and
- when both names denote function templates, the signatures (17.5.6.1) are the same.
The requirements appear to be satisfied, provided that the return types are in fact the same (since the return type is part of the signature for a class member function template, according to [defns.signature.member.templ]). Since foo<T>::x
is int
, they are the same.
This would not be the case if the type of x
were dependent. For example, GCC and Clang both reject the definition when the declaration of x
is changed to typename identity<T>::type x;
. [Coliru link] In that case, [temp.type]/2 would apply:
If an expression e is type-dependent (17.6.2.2),
decltype(
e)
denotes a unique dependent type. Two such decltype-specifiers refer to the same type only if their expressions are equivalent (17.5.6.1). [ Note: However, such a type may be aliased, e.g., by a typedef-name. — end note ]
Perhaps GCC is in error for considering x
to be type-dependent (it shouldn't be). However, this note suggests a workaround:
template <class T>
struct foo {
int x;
decltype(x) f1();
using x_type = decltype(x);
};
template <class T>
typename foo<T>::x_type foo<T>::f1() { return 0; }
This works on both GCC and Clang. [Coliru link]
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