clang / g cc несоответствие в специализации класса - PullRequest
9 голосов
/ 15 января 2020

Я сталкивался с этой проблемой, пытаясь специализировать tuple_size / tuple_element для пользовательского класса в C ++ 17 для структурированного связывания.

Ниже код компилируется в G CC, но не в clang (обе версии магистрали, см. ссылку ниже).

#include <type_traits>

template<typename T, typename... Ts>
using sfinae_t = T;

template<typename T, bool... Bs>
using sfinae_v_t = sfinae_t<T, typename std::enable_if<Bs>::type...>;

template <typename T>
struct Test;

template <typename T>
struct Test<sfinae_v_t<T, std::is_integral_v<T>>> {};

void f() {
    Test<int> t;
}

https://godbolt.org/z/ztuRSq

Это ошибка, предоставленная clang:

<source>:13:8: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list

struct Test<sfinae_v_t<T, std::is_integral<T>::value>> {};

       ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

1 error generated.

Compiler returned: 1

Это ошибка в компиляторе или код выше вызывает некоторый UB?

1 Ответ

3 голосов
/ 15 января 2020

То, что я скажу ниже (под СТАРЫЙ ПОСТ ), должно быть в некоторой степени правдой, но реальная проблема в том, что SFINAE используется неправильно, поэтому я больше не уверен, что это ошибка в г cc.

Объявление псевдонима всегда должно быть успешным, вы не можете SFINAE там, так как это не объявление класса или функции или специализации (это имеет смысл, поскольку вы не можете специализировать псевдонимы). Если объявление псевдонима не удается, программа некорректна. Следовательно, компилятор может предположить, что он никогда не придет к случаю, что объявление псевдонима не будет успешным, пока вы не заставите его создать такой шаблон.

Следовательно, для компилятора вполне приемлемо думать, что sfinae_v_t<T,...> всегда T, так как это произойдет, когда программа не является некорректной. Следовательно, он увидит, что во всех случаях, когда программа не является плохо сформированной, частичная специализация не специализируется, и поэтому она скажет вам, что это неправильно сформировано. (Это то, что делает Clang).

Я не думаю, что компилятор вынужден это делать. А если это не так, и он просто думает: «Хорошо, sfinae_v_t - это какой-то тип, что угодно», тогда не очевидно, что это переопределение. Поэтому я думаю, что до тех пор, пока мы не создадим один из них, нет ничего плохого в том, чтобы не выдавать ошибку.

Но когда мы его создаем, то должна возникать проблема, связанная с тем, что у нас есть переопределение или что программа плохо сформирована из-за до std::enable_if, в зависимости от аргумента шаблона. G CC должен взять хотя бы один из них, но не может.

Это также абсолютно не относится к более простому примеру без std::enable_if. Так что я все еще думаю, что это ошибка в G CC, но я достаточно ошеломлен, что не могу с уверенностью сказать это. Я бы сказал, что кто-то должен сообщить об этом как об ошибке и позволить людям из g cc подумать об этом.

OLD POST

Это ошибка в г cc. Стандарт дает нам правила для преобразования шаблона класса в шаблоны функций. Один шаблон класса более специализирован, чем другой, если его функция предшествует другой в упорядочении шаблона частичной функции.

Я создал функции здесь , и теперь g cc утверждает, что их вызов неоднозначен, поэтому следует также сказать, что шаблоны классов заданы одинаково.

Примечание: читая стандарт внимательно, компилятор в моей голове согласен с clang.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...