Look at this code:
template <typename T, void (T::*pfn)()> struct Testee {}; class Tester { private: void foo() {} public: using type_t = Testee<Tester, &Tester::foo>; };
It successfully compiles with g++ -std=c++14 -Wall -Wextra
.
However, when I change the order of foo
and type_t
, an error occurs:
$ cat test.cpp template <typename T, void (T::*pfn)()> struct Testee {}; class Tester { public: using type_t = Testee<Tester, &Tester::foo>; private: void foo() {} }; int main() { } $ g++ -std=c++14 -Wall -Wextra -pedantic test.cpp test.cpp:6:36: error: incomplete type ‘Tester’ used in nested name specifier using type_t = Testee<Tester, &Tester::foo>; ^ test.cpp:6:47: error: template argument 2 is invalid using type_t = Testee<Tester, &Tester::foo>; ^
Usually, the order of declarations in class definitions has no effect on name resolving. For example:
struct A // OK { void foo(int a = val) { } static constexpr const int val = 42; }; struct B // OK { static constexpr const int val = 42; void foo(int a = val) { } };
However, it has an effect in this case. Why?
This is not really related to templates. You get a similar error on:
class Tester { public: using type_t = decltype(&Tester::foo); private: void foo() {} };
It's true that a class is (Standard 9.2/2):
regarded as complete within function bodies, default arguments, using-declarations introducing inheriting constructors (12.9), exception-specifications, and brace-or-equal-initializers for non-static data members (including such things in nested classes).
However, the definition of a member type is not in that list, so it can only use names declared before that point.
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