Интерфейс подобен контракту, в котором вы хотите, чтобы ваш класс реализации реализовал методы, написанные в контракте (интерфейс). Поскольку Java не предоставляет множественное наследование, программирование для интерфейса является хорошим способом достижения цели множественного наследования. Если у вас есть класс A, который уже расширяет какой-либо другой класс B, но вы хотите, чтобы класс A также следовал определенным рекомендациям или реализовывал определенный контракт, тогда вы можете сделать это путем программирования стратегии интерфейса.
blockquote>
add_cv_t<T>
иconst volatile T
add_const_t<T>
иconst T
add_volatile_t<T>
иvolatile T
Нет разницы; определение
add_const<T>::type
является, например, толькоT const
.blockquote>
add_lvalue_reference_t<T>
иT&
add_rvalue_reference_t<T>
иT&&
T&
иT&&
плохо сформированы, когдаT
- cvvoid
, но эти шаблоны хорошо сформированы,blockquote>
add_pointer_t<T>
иT*
?
add_pointer_t<T>
эквивалентноstd::remove_reference<T>::type*
. То есть, еслиT
является ссылочным типом, он дает указатель на ссылочный тип. С другой стороны,T*
будет плохо сформирован, так как вы не можете иметь указатель на ссылку.Что вы должны использовать?
- В общем, псевдоним шаблоны могут использоваться для предотвращения вычета
T
. Конечно, это означает, что если вы хотите дедукции, вы должны избегать их.- Шаблоны псевдонимов могут использоваться в качестве аргументов шаблона шаблона для шаблона, который принимает преобразование типа в качестве параметра.
- Шаблоны псевдонимов, которые отличаются поведением от альтернатив, таких как
T*
, полезны в общем коде, поскольку они «делают правильные вещи». Например, еслиT
выводится из аргумента типаT&&
, тогдаT*
делает неправильную вещь, когда аргумент является lvalue, поскольку он пытается объявить указатель на ссылку lvalue. Ноstd::add_pointer_t<T>
даст указатель на фактический тип аргумента.
В большинстве случаев std::add_rvalue_reference_t<T>
эквивалентно T&&
. Тем не менее, правила свертывания ссылок и the-rules-that-dictate-which-types-are-referenceable могут иметь ваш код, если он не учитывается.
, в некоторых случаях, когда тип статического члена type
будет отличаться, поскольку T
является не ссылочным типом. Например, std::add_rvalue_reference_t<void>
разрешает void
и (используя другой шаблон, который вы упомянули в качестве примера) std::add_pointer_t<T&>
разрешает T*
(если вы хотите вызвать хаос, требуемый ритуал std::add_pointer_t<std::add_rvalue_reference_t<void>>
:))
Уважая использование, его можно использовать в качестве параметра шаблона шаблона, чтобы сделать какую-то чертову черную магию. Во всяком случае, такие вещи, как std::is_rvalue_reference_t<T>
или std::remove_reference_t<T>
, обычно чаще используются при манипулировании ссылочными атрибутами типа.
В соответствии с тем, что я вижу в источнике STL:
add_cv_t<T>
и const volatile T
- нет разницы
add_const_t<T>
и const T
- никакой разницы
add_volatile_t<T>
и volatile T
- нет разницы
add_lvalue_reference_t<T>
и T&
- существует разница, например, если T не является ссылочным типом void. add_lvalue_reference_t<void>::type = void
и void&
= ошибка времени компиляции
add_rvalue_reference_t<T>
и T&&
- то же, что и выше
add_pointer_t<T>
и T*
- разность, когда T потому что нет указателя на ссылку. add_pointer_t<T>
эквивалентно std::remove_reference<T>::type*