невідповідність кланг / гкц у спеціалізації класу


9

Я зіткнувся з цим питанням, намагаючись спеціалізуватися tuple_size/ tuple_elementдля спеціального класу на C ++ 17 для структурованого прив’язки.

Нижче код компілюється в GCC, але не в 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?


3
Це можна спростити ще більше .
Євг

3
І ICC, і MSVC не вдаються до компіляції.
ChrisMM

@Evg Дивно, що gccкомпілює це, бачачи, як це не збирає цього ...
Макс Ленгоф

1
FWIW це має бути неправильним формуванням, якщо я не повністю помиляюся (з тієї ж причини, що це неправильно формується).
Макс Лангхоф

1
оскільки ми цитуємо стандарт, я додав тег мови-юриста.
Гійом Ракікот

Відповіді:


3

Те, що я розповідаю нижче (під СТАРИМ ПОСТ ), повинно бути істинним, але актуальною проблемою є те, що SFINAE використовується неправильно, отже, я вже не впевнений, що це помилка в gcc.

Декларація псевдоніму завжди має бути успішною, ви не можете там SFINAE, оскільки це не декларація класу чи функції чи спеціалізації (це має сенс, оскільки ви не можете спеціалізувати псевдоніми). Якщо декларація псевдоніму не вдається, програма неправильно формується. Отже, компілятор може припустити, що він ніколи не прийде до того, що декларація псевдоніму не вдасться, поки ви не змусите його створити такий шаблон.

Отже, компілятору цілком прийнятно думати, що sfinae_v_t<T,...>це завжди T, оскільки це станеться, коли програма не буде сформована. Звідси видно, що у всіх випадках, коли програма не є сформованою, часткова спеціалізація не спеціалізується, і як така вона скаже вам, що це неправильно формується. (Ось що робить кланг).

Я не думаю, що компілятор змушений це робити. А якщо це не так, і просто думає «Добре, sfinae_v_tякийсь тип, що завгодно.», То не очевидно, що це передекларація. Тому я думаю, поки ми не створимо один із них, немає нічого поганого в тому, щоб не кинути помилку.

Але коли ми інстанціонуємо це, то повинна бути або проблема в тому, що у нас є передекларація, або в тому, що програма неправильно формується через std::enable_if, залежно від аргументу шаблону. GCC має забрати хоча б одну з них, але не робить жодної.

Це також абсолютно не стосується більш легкого прикладу без std::enable_if. Тож я все ще думаю, що це помилка в GCC, але я достатньо вражений, що більше не можу цього сказати з певністю. Я б просто сказав, що хтось повинен повідомити про це як про помилку і нехай люди з gcc подумають про це.

СТАРИЙ ПОСТ

Це помилка в gcc. Стандарт дає нам правила перетворення шаблону класу в шаблони функцій. Шаблон одного класу є більш спеціалізованим, ніж інший, якщо його функція приходить до впорядкування шаблону часткової функції.

Я створив тут функції і тепер gcc стверджує, що викликати їх неоднозначно, отже, слід було б також сказати, що шаблони класів однаково вказані.

Примітка: уважно читаючи стандарт, компілятор в моїй голові погоджується з кланг.


Існують sfinae_v_t<T, std::is_integral_v<T>>і sfinae_v_t<T, !std::is_integral_v<T>>розглядаються як ті ж типи? Семантично це не так.
OFO

@GuillaumeRacicot Цілком можливо, але я хотів би зрозуміти, чому саме так. Наприклад, стандарт також говорить: "Залежні імена не можуть бути перевірені при оголошенні часткової спеціалізації, але будуть перевірені при заміні на часткову спеціалізацію." Чи це не означає, що вони одного типу повинні вирішуватися після заміни Т на часткову спеціалізацію, оскільки sfinae_v_t<T>це залежить від T? У такому випадку вони не були б однаковими, оскільки будь-який з них буде неправильно сформований.
OFO

@ofo Треба сказати, я не впевнений. Трохи розумно навіть думати про цих двох, оскільки один з них ніколи не буде типом, а використання їх обох у нешаблонному контексті призведе до помилки компіляції через enable_if_t. Я найкраще читав цей стандарт, що це не має значення, вони однакові чи ні. Для часткового впорядкування ми завжди будемо порівнювати форму параметрів шаблону однієї функції з формою аргументу шаблону іншої (тобто intвже заміщений), і тоді в одному з них є дійсно тип, тому нам не доведеться порівнювати їх абстрактно.
n314159

1
Копаємо глибше, я знайшов це з тут . SFINAE має добре працювати з псевдонімами шаблонів, інакше template<bool B, typename T> enable_if_t = typename enable_if<B, T>::type;не працює. Я продовжую подавати помилку на gcc, але не дуже впевнений, чи gcc там не так. Дякую.
OFO
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.