Обнаружение поддержки оператора с помощью decltype / SFINAE
Вопрос
В (несколько) устаревшей статье рассматриваются способыиспользуйте decltype
вместе с SFINAE, чтобы определить, поддерживает ли тип определенные операторы, такие как ==
или <
.
Вот пример кода, чтобы определить, поддерживает ли класс оператор <
:
Это выводит true
, поскольку, конечно, std::string
поддерживает оператор <
.Однако, если я попытаюсь использовать его с классом, который не поддерживает оператор <
, я получаю ошибку компилятора:
Значит, СФИНАЭ здесь не работает.Я пробовал это на GCC 4.4 и GCC 4.6, и оба показали одинаковое поведение.Итак, можно ли использовать SFINAE таким образом, чтобы определить, поддерживает ли тип определенные выражения?
Решение
Вам необходимо сделать вашу функцию less_than_test шаблоном, поскольку SFINAE означает «Ошибка подстановки не является ошибкой», и в вашем коде нет функции шаблона, которая может вызвать сбой при выборе.
родовое словоДругие советы
В C ++ 11 самым коротким и общим решением, которое я нашел, было следующее:
родовое слово Работает с g++ 4.8.1
и clang++ 3.3
Более общее решение для произвольных операторов (ОБНОВЛЕНИЕ 2014 г.)
Существует более общее решение, использующее тот факт, что все встроенные операторы также доступны (и, возможно, специализированы) через оболочки операторов STD, такие как std::less
(двоичный) или std::negate
(унарный).
Это можно использовать в самом общем виде, особенно в C ++ 14, где определение типа откладывается до вызова оболочки оператора («прозрачные операторы»).
Для бинарных операторов это может использоваться как:
родовое словоДля унарных операторов:
родовое слово (Со стандартной библиотекой C ++ 11 все немного сложнее, потому что нет сбоев при установке decltype(std::less<random_type>()(...))
, даже если для random_type
не определена операция, можно вручную реализовать прозрачные операторы в C ++ 11, которые являются стандартными в C ++ 14)
Синтаксис довольно плавный. Надеюсь, что-то подобное будет принято в стандарте.
Два расширения:
1) Он работает для обнаружения приложений с исходными функциями:
родовое слово 2) Он может дополнительно определить, является ли результат конвертируемым / сопоставимым с определенным типом, в этом случае поддерживается double < double
, но будет возвращено значение false во время компиляции, потому что результат не указан.
Примечание: я только что попытался скомпилировать код с C ++ 14 в http:// melpon.org/wandbox/ , и это не сработало. Я думаю, что есть проблема с прозрачными операторами (такими как std::less<>
) в этой реализации (clang ++ 3.5 c ++ 14), поскольку когда я реализую свой собственный less<>
с автоматическим выводом, он работает хорошо.
Это C ++ 0x, нам больше не нужны трюки, основанные на генерации кода тегов ...; -]
родовое слово (Это основано на ответе iammilind, но не требует, чтобы тип возвращаемого значения sizeof
был другого размера, чем T
, и не требует, чтобы operator<
создавался по умолчанию.)
Ниже приведен простой код, удовлетворяющий вашим требованиям (если вы не хотите ошибки компиляции):
родовое словоИспользование:
родовое слово [Примечание: если вам нужна ошибка компиляции для классов, не имеющих кода operator <
, это очень легко сгенерировать с помощью очень небольшого количества строк кода.]
@xDD действительно правильный, хотя его пример немного ошибочен.
Это компилируется на идеоне:
родовое словоРезультат:
родовое словоСм. здесь в действии.
Дело в том, что SFINAE применяется только к функциям шаблона.