Когда компилятору необходимо вычислить псевдоним?

Рассмотрим следующий код:

template <class T>
struct computation {
    using type = /* something based on T that takes time to compile */;
};

Теперь рассмотрим два кода:

using x = computation<T>;

и:

using y = typename computation<T>::type;

Мне интересно, подразумевает ли стандарт, что:

  • Вариант А) Любой "разумный" компилятор приведет к быстрому времени компиляции для x и долгому времени компиляции для y
  • Вариант Б) Компилятор может полностью вычислить computation<T>::type, даже если вызывается только computation<T>, что приводит к длительному времени компиляции даже для x

Другими словами, я пытаюсь узнать, указывает ли стандарт что-либо, что, скорее всего, приведет к варианту A или варианту B для «разумного» компилятора. Я знаю, что стандарт ничего не говорит о реализации компилятора, но, например, если он требует, чтобы ::type не обязательно существовал до тех пор, пока он не будет вызван специально, это будет в пользу варианта A.

ПРИМЕЧАНИЕ: По своему опыту я почти уверен, что g++, clang++, msvc и intel следуют варианту A), но я понятия не имею, является ли это чистой случайностью или связано с чем-то в стандарте.

Кто-то может доказать, что я ошибаюсь, но учтите возможность того, что стандарт ничего не говорит о скорость компиляции при определении типа.

Drew Dormann 09.05.2022 03:50

Я знаю это, и это не то, что я пытаюсь узнать. Но если в стандартах сказано, что ::type на самом деле не «существует», пока его не вызовут, это будет убедительным признаком.

Vincent 09.05.2022 03:52

Я думаю, что компилятор должен выбрать вариант B, потому что он должен убедиться, что computation<T>::type действительно дает что-то разумное при сопоставлении с T. Но, может быть, просто попробуйте. Сделайте ::type fail для T и посмотрите, работает ли using x = computation<T>;.

Goswin von Brederlow 09.05.2022 04:00

@GoswinvonBrederlow См. добавленную заметку

Vincent 09.05.2022 04:19

iirc, стандарт требует минимальной глубины стека (которая действительно мала), но компиляторы могут предоставить более глубокую глубину стека, если они хотят.

Eljay 09.05.2022 04:20

Я не знаю, указано ли это явно где-либо в стандарте, раздел шаблона и ODR несколько утомительны для чтения, но правило «как если бы» дает компиляторам большую свободу действий, и я ожидаю, что вариант A был тем, что больше всего/ все компиляторы используют. Если что-то никогда не используется, у компилятора нет причин выполнять эту работу.

NathanOliver 09.05.2022 04:34

@NathanOliver Что, если ::type выдает ошибку для заданного T, которая очевидна только тогда, когда вы выполняете работу, и поэтому вывод шаблона должен завершиться неудачно?

Goswin von Brederlow 09.05.2022 05:05

T в двух строках using должен быть фактическим типом или другим параметром шаблона? В первом случае typename не имеет смысла, а во втором случае ни одна из строк сама по себе не вызовет никаких экземпляров чего-либо.

user17732522 09.05.2022 11:08

@GoswinvonBrederlow: компиляторам разрешено выполнять работу, которая не является строго необходимой, но они не могут отклонять действительные программы. Поскольку computation<T> само по себе не является явным или неявным воплощением, действительность type не имеет значения.

MSalters 09.05.2022 13:00
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
9
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я предполагаю, что T здесь является независимым типом, а не другим параметром шаблона.


Линия

using x = computation<T>;

не вызывает неявную реализацию computation<T>. Поэтому у компилятора нет причин пытаться вычислить type в этот момент, в частности, поскольку любой сбой создания экземпляра нужно будет игнорировать. Программа не может не скомпилироваться, если вычисление type даст недопустимый тип или по какой-либо иной причине завершится ошибкой.

Линия

using y = computation<T>::type;

требует неявного создания экземпляра computation<T>, потому что к нему применяется оператор разрешения области видимости. Неявная реализация включает в себя вычисление псевдонимов типов внутри computation<T>. Компилятор должен выполняет вычисление, потому что, если вычисление завершится ошибкой или будет получен недопустимый тип, программа будет неправильно сформирована, и компилятору придется ее диагностировать.

На самом деле это не зависит конкретно от части ::type. Даже если это было ::type2 для псевдонима другого типа, неявное создание экземпляра специализации шаблона класса потребует вычисления type.

Точно так же использование computation<T> в любом другом контексте, требующем его завершения, потребует неявного создания экземпляра и, следовательно, вычисления type, например.

auto z = computation<T>{};

Другие вопросы по теме