Ссылка на конкретную специализацию шаблона из неинстанцированного контекста: инстанцирование или нет?
Рассмотрим следующий пример
template <typename A> struct S
{
A a;
void foo() {}
};
template <typename T> void bar()
{
S<void> *p = 0;
}
template <typename T> void baz()
{
S<void>{}.foo();
}
template <typename T> void qux()
{
S<void> s{};
}
int main()
{
}
Шаблоны функций bar
, baz
а также qux
преднамеренно оставлены неустановленными.
Определение baz
не компилируется в GCC и Clang по "очевидной" причине - S<void>
неверная специализация S
, Однако какое правило языка работает в этом случае?
С одной стороны,
S<void>
не зависит от параметров шаблонаbaz
, членский доступ требует, чтобы он был завершен, что запускает созданиеS<void>
, который терпит неудачу. Диагностика обязательна.С другой стороны, у нас есть общее правило: "если для неинстанцированного шаблона не может быть сгенерировано действительной специализации, код некорректен". Это делает определение
baz
плохо сформирован. Однако никакой диагностики не требуется.
Более конкретно, я прав в своем предположении (как выражено в #1), что приведенная выше ссылка на S<void>
из неосуществленных baz
требует создания экземпляров S<void>
? Предположение подтверждается тем фактом, что оба компилятора с радостью принимают определение bar
, который не является экземпляром S<void>
,
Тем не менее, вышеупомянутые компиляторы отличаются по своему qux
- Clang жалуется, в то время как GCC принимает его без каких-либо жалоб. Это ошибка в одном из компиляторов? Требуется ли в этом случае диагностика? Или я ошибаюсь, полагая, что № 1 здесь на работе? Если № 2 является основой для диагностики, то разница между компиляторами является приемлемой.
2 ответа
И то и другое S<void>{}
а также S<void> s{}
используются в контексте, требующем S<void>
, такой экземпляр плохо сформирован из-за члена, имеющего неполный тип void
,
Соответствующие цитаты [temp.inst]/1
:
Если специализация шаблона класса не была явно создана или явно специализирована, специализация шаблона класса создается неявно, когда на специализацию ссылаются в контексте, который требует полностью определенного типа объекта или когда полнота типа класса влияет на семантику программы, [...]
а также [temp.arg]/6
:
Если использование шаблона-аргумента приводит к неправильной конструкции при создании шаблона специализации, программа является плохо сформированной.
С другой стороны, оба baz
а также quz
плохо сформированы НДР[temp.res]/8
:
Знание того, какие имена являются именами типов, позволяет проверять синтаксис каждого шаблона. Программа некорректна, диагностика не требуется, если:
(8.1) для шаблона не может быть сформирована действительная специализация, [...]
Для обоих baz
а также qux
, действительность выражения в том числе S<void>
может быть сделано только посредством создания экземпляра S. Тем не менее, компиляторы не обязаны выполнять эту проверку перед любой реализацией [temp.res]/8
Срок действия шаблона может быть проверен до любого экземпляра. [... ] Программа некорректна, диагностика не требуется, если:
- гипотетическое создание шаблона сразу после его определения будет некорректным из-за конструкции, которая не зависит от параметра шаблона,