«Шаблон класса уже определен» при создании похожих, но разных специализаций

У меня две классовые специализации. Я хочу, чтобы один из них использовался, когда существует T::A, а другой — когда существует T::B, что на практике должно быть взаимоисключающим. Я использую std::void_t< decltype( ... ) > для проверки существования. Я ожидаю, что это выражение не сможет оценить ни ту, ни другую специализацию, и поэтому я ожидаю, что SFINAE приведет к игнорированию одной из специализаций.

template< typename T, typename Enable = void >
class C{};

template< typename T >
class C< T, std::void_t< decltype( T::A ) > > {};

template< typename T >
class C< T, std::void_t< decltype( T::B ) > > {};

Однако MSVC просто дает мне

(On line containing T::B): error C2953: 'C<T,void>': class template has already been defined
(On line containing T::A): note: see declaration of 'C<T,void>'

Что я делаю не так?

void_t всегда void, поэтому нет никакой разницы между первым и этими двумя
Swift - Friday Pie 24.11.2022 00:03

Но в документации для std::void_t конкретно сказано, что это и есть его цель: en.cppreference.com/w/cpp/types/void_t

John Haggerty 24.11.2022 00:06

Но являются ли T::A и T::B взаимоисключающими в вашем реальном коде?

Useless 24.11.2022 00:27

Ошибки компиляции возникают даже без попытки использовать класс для каких-либо фактических типов.

John Haggerty 24.11.2022 01:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Clang также отвергает этот код, но не GCC. Уже не первый раз вижу проблемы с std::void_t.

Я бы держался подальше от этого и предпочел бы decltype(void(T::A)).

Или вы можете определить свой собственный надежный void_t (код взят из cppreference):

template<typename... Ts> struct make_void { typedef void type; };
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

Замена void_t этой реализацией, похоже, решает проблему. Как вы думаете, это ошибка в компиляторе MSVC или в их реализации STL? Любая идея, если есть способ сообщить об этом?

John Haggerty 24.11.2022 00:18

gcc не выберет ни шаблон с std::void_t, ни ваш void_t. Он выберет шаблон по умолчанию.

Swift - Friday Pie 24.11.2022 00:19

@Swift-FridayPie Мне подходит с обоими void_t вкусами. Возможно, вы определяете A и B как типы?

HolyBlackCat 24.11.2022 00:28

@JohnHaggerty Я считаю, что определение исправлено в стандарте, но это может быть ошибка компилятора. Вы можете попробовать подать его и посмотреть, что произойдет. Вы также можете сообщить об этом Clang. Обязательно сначала проверьте существующие отчеты.

HolyBlackCat 24.11.2022 00:30

@HolyBlackCat поцарапайте, кажется, void_t механика не в ладах с видимостью T::A , T::B. Они должны быть public. Это может быть связано с проблемой ОП.

Swift - Friday Pie 24.11.2022 00:58

@JohnHaggerty Под «исправлено в стандарте» я имею в виду, что для этого требуется конкретное определение (тот, который без вспомогательной структуры).

HolyBlackCat 24.11.2022 07:39

Другие вопросы по теме