Ссылка на конкретную специализацию шаблона из неинстанцированного контекста: инстанцирование или нет?

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

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, Однако какое правило языка работает в этом случае?

  1. С одной стороны, S<void> не зависит от параметров шаблона baz, членский доступ требует, чтобы он был завершен, что запускает создание S<void>, который терпит неудачу. Диагностика обязательна.

  2. С другой стороны, у нас есть общее правило: "если для неинстанцированного шаблона не может быть сгенерировано действительной специализации, код некорректен". Это делает определение 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

Срок действия шаблона может быть проверен до любого экземпляра. [...  ] Программа некорректна, диагностика не требуется, если:

  • гипотетическое создание шаблона сразу после его определения будет некорректным из-за конструкции, которая не зависит от параметра шаблона,
Другие вопросы по тегам