Нет, это действительно невозможно.
Сейчас это языковая проблема — имя класса не существует до того, как оно будет записано в коде. Но даже если бы компилятор C++ прочитал файл за несколько проходов и знал имена, этого все равно было бы недостаточно. Разрешить это либо потребовало бы существенного изменения системы типов и не в лучшую сторону, либо это было бы в лучшем случае очень хрупким решением. Позволь мне объяснить.
Гипотетически, если бы это имя могло быть упомянуто в предложении requires
, код также потерпел бы неудачу, потому что T=Me
на данный момент все еще является неполным типом. @Justin продемонстрировал, что в своем замечательном комментарии мой ответ основан на нем.
Но чтобы не заканчивать это здесь и не быть очень скучной версией Вам нельзя делать, давайте спросим себя, почему Me
неполное?
Взгляните на следующий довольно надуманный пример и убедитесь, что узнать полный тип Me
внутри его базового класса невозможно.
#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
{
};
Это, конечно, не что иное, как версия C++ парадокса Рассела, которая демонстрирует, что четко определенный объекты/наборы не могут быть определены с использованием самих себя.
Итак, какова ценность std::is_base_of_v<Foo,Me>
? То есть Me
происходит от Foo
?
Если это не так, то в этом случае условие в классе Negator
истинно, и, таким образом, Me
происходит от Negator<Me>::type
, то есть Foo
, что является противоречием.
С другой стороны, если оно происходит от Foo
, мы обнаруживаем, что на самом деле это не так.
Это может показаться искусственным примером, и, в конце концов, вы спросили о чем-то другом. Да, вероятно, существует конечное число абзацев, которые вы могли бы добавить в Стандарт, чтобы разрешить конкретное использование вашего Wrapper
и запретить мое использование Negator
, но между этими не столь уж несходными примерами должна быть проведена очень тонкая грань.
Эта потребность в ранней завершенности до того, как };
сломает sizeof
, что, вероятно, является более распространенным аргументом:
sizeof(Me)
очевидно зависит от размера всех базовых классов. Таким образом, использование выражения внутри базового класса, который все еще пишется, а потому не может быть полным по определению и не иметь размера, — это еще одна мина, ожидающая, когда вы наступите на нее.
Тем не менее, еще более простой пример:
struct Me
{
int x[sizeof(Me)];
};
Трюк с другом
Я полагаю, вы говорите об этом этом. Да, это работает, но по той же причине, по которой вы поставили requires
рядом с методами, которые сработали. Удаляемый или недоступный конструктор проверяется только тогда, когда его вызов действительно сгенерирован, что обычно происходит только тогда, когда создается экземпляр, и в этот момент Me
является полным типом.
Это также сделано по уважительной причине, вы бы хотели, чтобы этот код работал:
struct Me
{
int size(){
return sizeof(Me);
}
};
Метод не может влиять на тип Me
, так что это не создает никаких проблем.
person
Quimby
schedule
07.12.2020
static_assert(std::derived_from<T, Wrapper<T>>)
после открывающей скобки в этом случае не работает, так какT
неполный godbolt.org/z/ у-jVGZ - person Justin   schedule 30.06.2020