Это строго определено стандартом, как эта программа должна компилироваться? - PullRequest
0 голосов
/ 24 октября 2018

Следующая программа была создана для злоупотребления некоторыми особенностями двухфазного поиска в gcc / msvc.Он прекрасно компилируется как с gcc / msvc, так и clang, но приводит к отличному возвращаемому значению от функции g:

struct A;
struct C {};

struct D {
    D (const A &);
};

struct B {
    void f (const C&,int){x=0;};
    void f (const D&,char){x=1;};
    int x;
};

template<typename T>
int f(const A &y)
{
    B x;
    x.f(y,0);   // Line 18
    return x.x;
}

struct A
{
    operator C () const;
};

int g (const A&x)
{
    return f<int>(x);
}

https://gcc.godbolt.org/z/pqAVsU

И GCC, и MSVC вызывают A::operator C и возвращают0, в то время как Clang вызывает D(const A &) и возвращает 1.

Верно ли в соответствии со стандартом, что clang является правильным, и вызов в строке 18 должен быть разрешен, в то время как struct A еще не объявлен, или это такнеопределенного поведения?

Ответы [ 2 ]

0 голосов
/ 24 октября 2018

Программа некорректна, диагностика не требуется, в соответствии с [temp.res] / 8 :

Достоверность шаблона может быть проверена перед любымконкретизации.[Примечание: Зная, какие имена являются именами типов, можно таким образом проверять синтаксис каждого шаблона.- конец примечания] Программа некорректна, диагностика не требуется, если:

  • ...

  • интерпретация такой конструкциив гипотетической реализации отличается от интерпретации соответствующей конструкции в любой фактической реализации шаблона.[Примечание: это может произойти в следующих ситуациях:

    • тип, используемый в независимом имени, является неполным в точке, в которой определен шаблон, но завершен в точкев котором выполняется экземпляр, или

    • ...

  • ...

В вашей программе y является независимым именем, а его тип A является неполным в определении f, но завершается, когда создается экземпляр f<int>, поэтому правило вышеприменяется.

0 голосов
/ 24 октября 2018

[ temp.dep.candidate ] говорит, и это может иметь отношение к сбоям компилятора (примечания и акцент мой):

Для вызова функции, где postfix-expression [это выражение, которое обозначает функцию, здесь f] является зависимым именем, функции-кандидаты находятся с использованием обычных правил поиска ([basic.lookup.unqual], [basic.lookup.argdep]) за исключением того, что:

  • [Описание поведения 2PL / ADL]

Если вызов будет некорректным или найдетДля лучшего соответствия в результате поиска в связанных пространствах имен рассматривались все объявления функций с внешними связями, введенные в эти пространства имен во всех единицах перевода, а не только те объявления, которые были найдены в контекстах определения шаблона и создания экземпляра шаблона, затем программаимеет неопределенное поведение .

Однако x.f(y,0); не не зависит от T в любой точке, поэтому страшная параграPh выше не относится.Мы находимся в случае независимого поиска, охватываемого [ temp.nondep ] (обратите внимание, мое):

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

Все выражение должно быть разрешено в контексте определения ::f, когда точка A является неполной, а оператор преобразования - , а не видимый.Clang прав, а GCC и MSVC оба не правы.

...