No, this is really not possible.
Right now it is a language problem - the name of the class does not exist before it is actually written in the code. But even if the C++ compilers read the file in multiple passes and knew the names, it would still not be enough. Allowing this would either require a major change of the type system, and not for the better, or it would be a very brittle feature at best. Let me explain.
Hypothetically if the name could be mentioned in the requires
clause, the code would also fail because T=Type
is still an incomplete type at this point. @Justin demonstrated that in his noteworthy comment my answer builds upon.
But to not make it end here and be a very boring version of "You are not allowed to do that" lets ask ourselves why is Me
incomplete in the first place?
Take a look the following rather contrived example and see that knowing the full type of Me
is impossible inside its base class.
#include <type_traits>
struct Foo;
struct Bar{};
template<typename T>
struct Negator {
using type = std::conditional_t<!std::is_base_of_v<Foo,T>, Foo, Bar>;
};
struct Me: Negator<Me>::type{};
This is of course nothing else than C++ version of Russell's paradox which demonstrates that well-defined types/sets cannot be defined using themselves.
A simple question: is Foo
a base class of Me
? I.e. what is the value of std::is_base_of_v<Foo,Me>
?
- If it is not, the conditional in
Negator
is true and therefore Me
is deriving from Negator<Me>::type
i.e. Foo
which is a contradiction.
- On the other hand, if it does derive from
Foo
, we find out it actually does not.
It might seem like an artificial example and it is, you did ask about something else after all.
Yes, there probably is a finite number of paragraphs you could add to the Standard to allow that particular usage of your Wrapper
and disallow my usage of Negator
, but there would have to be drawn a very thin line between these not so dissimilar examples.
Another example of the need for early incompleteness before };
is the usage of sizeof
which is probably a more commonly given argument:
sizeof(T)
obviously depends on the size of all base classes. So using the expression inside a base class Wrapper
of a derived type T
that is still being written is another land mine waiting for you to step on.
Still, even easier example without any inheritance is:
struct Me
{
int x[sizeof(Me)+1];
};
What is the size of Me
?
The "friend trick"
I believe you are speaking about Prevent user from deriving from incorrect CRTP base. Yes, that works but for the same reason you putting requires
near the methods worked. The constructor being deleted or inaccessible is checked only when its call is actually generated, which usually is only when an instance is created and at that point Me
is a complete type.
This is also done for a good reason, you would want this code to work:
struct Me
{
int size(){
return sizeof(Me);
}
};
Existence of a method cannot influence the type of Me
, so this does not create any problems.