Использовать случаи для std:: add_const и аналогичных
Некоторые преобразования типов в <type_traits>
также могут быть выражены с использованием синтаксиса основного языка (например, std::add_const<T>::type
is/кажется эквивалентным const T
). Dtto для std::add_lvalue_reference
и, возможно, других. Какая польза от этих черт типа?
Я полностью понимаю, что стандарт будет предоставлять "неполный набор инструментов" без них, и я могу представить себе мета-путь, примерно так:
template<typename In, template <typename> class Modifier>
struct Apply {
typedef typename Modifier<T>::type Out;
};
Apply<int, std::add_const>
Существуют ли какие-либо другие варианты использования этих признаков, которые могут быть выражены синтаксически, или они просто включены "из чувства полноты" и для случайного мета-использования?
Ответы
Ответ 1
Эти черты исходят от Boost и предложения о добавлении их в стандарт, N1345, цитирует Андрея Александреску:
"Я понимаю аргумент симметрии для добавления add_const
, add_volatile
, add_cv
и add_pointer
, однако я бы сказал, что они устраняют их. Эквиваленты, предоставляемые языком, просто проще и приятнее".
То же предложение также дает такое обоснование:
Замечание автора: поверхностно классы add_const, add_volatile и add_cv не имеют значения, поскольку, например, add_const:: type такой же, как T const, для всех T (в настоящее время это не относится к типам функций, но issue 295). Однако опыт повышения эффективности заключается в том, что несколько пользователей попросили, чтобы эти шаблоны присутствовали в библиотеке по следующим причинам: (a) Некоторые пользователи находят их более явными - при объединении шаблонов преобразования, в частности, пользователи, такие как "встроенные" документация ", которую предоставляют эти шаблоны. (b) Не все пользователи знают, что cv-квалификация ссылки разрешена и не имеет никакого эффекта, или что cv-квалификационный тип, который уже имеет квалификацию cv, разрешен и не имеет никакого эффекта. (c) Компиляторы могут выдавать предупреждения, когда cv-квалификацию типа, который является ссылкой, или уже имеет cv-квалификатор, эти шаблоны могут быть реализованы таким образом, что эти сообщения в этих случаях подавляются.
Кроме того, для add_reference
(переименовано в add_lvalue_reference
в стандарте):
Примечание автора: шаблон add_reference был одним из оригинальных мотивов для библиотеки признаков типа boost. Однако разрешение вопроса 106 заставляет шаблон выглядеть в значительной степени избыточным. Несмотря на то, что add_reference может быть полезно при подавлении предупреждений компилятора, когда непреднамеренно создает ссылки на ссылки в коде шаблона.
Ответ 2
Эти черты предоставляются для случайного мета-использования. Это позволяет передавать требуемые cv-квалификаторы в метапрограммирование.
template<class T,template<class> class Trait>
struct transform
{
/* working with T creating newT*/
typedef Trait<newT>::type type;
};
template<class T>
struct special_transform
: transfrom<T, std::add_const>
{};
В этом случае вы не можете заменить std::add_const
на const
.
Ответ 3
Единственный случай использования, который я знаю, показан ниже:
struct F
{
bool f() const { return true; }
bool f() { return false; }
};
assert(!F{}.f())
assert(std::add_const_t< F >{}.f());
Он также необходим для тестирования функциональности функциональных функций cv-ref-qual, которые могут различаться для разных перегрузок (только для lref-квалифицированных современных С++ имеет удобную функцию std::as_const
):
struct F
{
int g() & { return 1; }
int g() const & { return 2; }
int g() && { return 3; }
int g() const && { return 4; }
};
F f;
assert(f.g() == 1);
assert(std::as_const(f).g() == 2);
assert(F{}.g() == 3);
assert(std::add_const_t< F >{}.g() == 4); // rarely needed, but if needed, then it helps
Ответ 4
add_const
может использоваться для разрешения конфликтов вывода типов.
template <typename T>
class wrapper;
template <typename T>
bool operator==(wrapper<T> const& w, T const& t);
Проблемы возникают, если мы используем wrapper<T const>
:
wrapper<int const> w = { 42 };
assert(w == 42); // Error: conflicting deduced types
T
одновременно выводится как int
, так и int const
. Это можно решить, используя add_const
:
template <typename T>
bool operator==(wrapper<T> const& w, add_const_t<T>& t);