Специализация класса с постоянным значением в std::enable_if

Я писал частичную специализацию для класса, когда параметр шаблона является производным от определенного типа. Моя реализация выглядит следующим образом:

struct base {};
struct derived: public base {};

template <typename T, typename=void>
struct foo {
    foo() { std::cout << "Version 1" << std::endl; } 
};

template <typename T>
struct foo <T, typename std::enable_if<std::is_base_of<base, T>::value>::type> {
    foo() { std::cout << "Version 2" << std::endl; }
};

Это работает, как и ожидалось: когда я создаю экземпляр foo<int>, конструктор печатает Version 1, а когда я создаю экземпляр foo<derived>, конструктор печатает Version 2.

Теперь я кое-что тестировал и хотел отключить частичную специализацию, поэтому я просто изменил ее на -

template <typename T>
struct foo <T, typename std::enable_if<false>::type> {
    foo() { std::cout << "Version 2" << std::endl; }
};

Я просто заменил std::is_base_of<base, T>::value на константу false. Но на этот раз компилятор начал выдавать предупреждения типа std::enable_if<false, void> не имеет type.

Почему оно так себя ведет? Почему здесь не работает SFINAE? Почему параметр std::enable_if ДОЛЖЕН зависеть от параметра шаблона?

Типы данных JavaScript
Типы данных JavaScript
В JavaScript существует несколько типов данных, включая примитивные типы данных и ссылочные типы данных. Вот краткое объяснение различных типов данных...
Как сделать движок для футбольного матча? (простой вариант)
Как сделать движок для футбольного матча? (простой вариант)
Футбол. Для многих людей, живущих на земле, эта игра - больше, чем просто спорт. И эти люди всегда мечтают стать футболистом или менеджером. Но, к...
Знайте свои исключения!
Знайте свои исключения!
В Java исключение - это событие, возникающее во время выполнения программы, которое нарушает нормальный ход выполнения инструкций программы. Когда...
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик
CSS Flex: что должен знать каждый разработчик Модуль flexbox, также известный как гибкий модуль разметки box, помогает эффективно проектировать и...
Введение в раздел &quot;Заголовок&quot; в HTML
Введение в раздел "Заголовок" в HTML
Говорят, что лучшее о человеке можно увидеть только изнутри, и это относится и к веб-страницам HTML! Причина, по которой некоторые веб-страницы не...
3
0
64
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
Почему здесь не работает SFINAE?

SFINAE расшифровывается как «сбой замены не является ошибкой». Если ваш аргумент для std::enable_if не зависит, то замены нет, и поэтому имеет смысл, что он не будет применяться.

В частности, стандарт говорит, что программа неправильно сформирована, диагностика не требуется, если

гипотетическая реализация шаблона сразу после его определения будет неправильно сформирована из-за конструкции, которая не зависит от параметра шаблона, [...]

(из [temp.res.general]/8.4) проекта N4868 после C++20)

Std::enable_if<false>::type не зависит и неправильно сформирован сразу после определения вашего шаблона.

В качестве продолжения я бы использовал sizeof(T) == 0. Это всегда false в стандартном коде.

Patrick Roberts 12.02.2023 23:56

Ну, это ответ на вопрос! Спасибо за ссылку на язык из стандарта. Означает ли это, что если я создам тип template <typename T> always_false { constexpr bool value = false} и буду использовать always_false<T>::value внутри enable_if, это будет нормально? Или этот шаблон тоже всегда искажен?

Ajay Brahmakshatriya 12.02.2023 23:56

@AjayBrahmakshatriya Можно поспорить, делает ли timsong-cpp.github.io/cppwp/n4868/temp.res.general#8.1 все еще IFNDR, но на практике все должно быть хорошо, да.

user17732522 12.02.2023 23:57

@PatrickRoberts См. комментарий выше.

user17732522 12.02.2023 23:58

@ user17732522 попался! Я буду использовать sizeof(T) == 0. Надеюсь, нигде в стандарте не сказано, что размер шрифта не может быть равен 0.

Ajay Brahmakshatriya 13.02.2023 00:00

Хорошо, конечно, технически это неправильно, и вы не хотели бы оставлять готовый код таким (как упоминалось в вопросе, это было временно для целей тестирования), но «диагностика не требуется», потому что на практике требуется, чтобы компилятор проверьте, что в каждом шаблоне определение непомерно дорого, и ни одна известная мне реализация не будет явно запрещать это.

Patrick Roberts 13.02.2023 00:01

@PatrickRoberts О, понятно! Я думаю, что в качестве последней попытки стандартного соответствия я мог бы использовать std::is_same<a_sentinel_type_nobody_should_use, T>::value, чтобы он даже компилировался. И да, я бы все равно не оставил это в кодовой базе, это было просто для тестирования чего-то

Ajay Brahmakshatriya 13.02.2023 00:03

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