Учитывая следующий пример кода
struct S;
template<typename>
class C
{
public:
void f(bool b)
{
if (b)
g();
}
void g()
{
S{};
}
};
int main()
{
C<int>{}.f(false);
}
GCC правильно сообщает следующее:
example.cpp: In instantiation of 'void C< <template-parameter-1-1> >::g() [with <template-parameter-1-1> = int]':
10 : required from 'void C< <template-parameter-1-1> >::f(bool) [with <template-parameter-1-1> = int]'
21 : required from here
15 : error: invalid use of incomplete type 'struct S'
Мой вопрос сейчас: это гарантированное поведение, которое имеет какое-то правило в стандарте или любых других документах?
Чтобы быть более точным в моем вопросе:
C
класс шаблона, члены которого f()
а также g()
создаются только тогда, когда на них ссылаются. f()
упоминается в main()
, Если я не ссылаюсь g()
(который внутренне пытается использовать неполный тип), код будет компилироваться. Но g()
ссылается внутри if-ветви внутри f()
, Эта ветвь детерминированно никогда не выполняется. Таким образом, компилятор может потенциально игнорировать / удалить эту ветку мертвого кода и, таким образом, избежать создания экземпляра g()
(и с этим ошибка попытки использовать неполный тип). Однако этого не происходит (на компиляторах я пробовал хотя бы).
Я понимаю, что разрешение этого превратит недопустимый код в допустимый код, просто корректируя настройки оптимизации компилятора, но все же мой вопрос заключается в том, гарантированно ли этот пример кода потерпит неудачу из-за некоторых правил (например, порядок оптимизации или проходов шаблона), которые можно где-то прочитать.
Спасибо за любые идеи.
Могут ли оптимизации встраивания и удаления мертвого кода предотвратить создание шаблона?
Нет.
Удаление мертвого кода — это оптимизация, которая может быть выполнена для удаления кода, который не «используется» в соответствии с правилами оптимизатора. Такая оптимизация не может нарушать правило «как будто», если реализация желает оставаться полностью совместимой.
Эта программа в любом случае плохо сформирована. Создание экземпляров C<int>
требуется, в полном объеме, по телефону, найденному в main
… и это невозможно. Если это создание было успешным, то его неиспользованные части могли быть оптимизированы, но это на шаг «позже». Вы можете удалить только те неиспользуемые части программы, которые изначально были физически способны «существовать».
Может быть интересно спросить, является ли реализация требуется чтобы предотвратить компиляцию такой плохо сформированной программы, если она впоследствии все равно удалит нарушающий код. Мы могли бы легко ответить на это, цитируя любой отрывок стандарта, определяющий «плохо сформированны黆. Но это и другой вопрос, и, на мой взгляд, кстати.
† Если вам интересно, мы не можем ответить на этот вопрос утвердительно в общем случае, так как некоторые случаи дурного обращения квалифицируются фразой «диагностика не требуется». Впрочем, если не считать этой фразы, то с головы до головы является требуется. (Не держи меня за это.)
Оптимизация — это то, что компилятору разрешено применять к действительной программе. Поскольку S не определено, его нельзя создать, а ваша программа недействительна. Слишком поздно для работы оптимизатора, чтобы сделать программу действительной.