Я видел эту мета-функцию, но никогда не понимаю, почему и в каком контексте это требуется. Может ли кто-нибудь объяснить это на примере?
template <typename T>
struct identity
{
using type = T;
};
Я видел эту мета-функцию, но никогда не понимаю, почему и в каком контексте это требуется. Может ли кто-нибудь объяснить это на примере?
template <typename T>
struct identity
{
using type = T;
};
Предотвращает вычет аргумента шаблона:
template <typename T>
void non_deducible(typename identity<T>::type t) {}
non_deducible(1); // error
non_deducible<int>(1); // ok
template <typename T>
void first_deducible(T a, typename identity<T>::type b) {}
first_deducible(5, 'A'); // ok
Отключает небезопасные/нежелательные неявные руководства по вычитанию (c++17):
template <typename T>
struct smart_ptr {
smart_ptr(typename identity<T>::type* ptr) {}
};
smart_ptr{new int[10]}; // error
smart_ptr<int>{new int}; // ok
Улучшает определение характеристик типа (и других метафункций):
template <typename T>
struct remove_pointer : identity<T> {};
template <typename T>
struct remove_pointer<T*> : identity<T> {};
Может использоваться для диспетчеризации тегов:
void foo(identity<std::vector<int>>) {}
void foo(identity<std::list<int>>) {}
template <typename T>
void bar(T t) {
foo(identity<T>{});
}
Может использоваться для возвращаемых типов:
template <int I>
constexpr auto foo() {
if constexpr (I == 0)
return identity<int>{};
else
return identity<float>{};
}
decltype(foo<1>())::type i = 3.14f;
Помогает специализировать функции, принимающие ссылку на пересылку:
template <typename T, typename U>
void foo(T&& t, identity<std::vector<U>>) {}
template <typename T>
void foo(T&& t) { foo(std::forward<T>(t), identity<std::decay_t<T>>{}); }
foo(std::vector<int>{});
Предоставляет альтернативный синтаксис для объявления типов, например указатели/ссылки:
int foo(char);
identity<int(char)>::type* fooPtr = &foo; // int(*fooPtr)(char)
identity<const char[4]>::type& strRef = "foo"; // const char(&strRef)[4]
Может использоваться как оболочка для кода, ожидающего существования вложенного T::type
или отсрочки его оценки:
struct A {};
struct B { using type = int; };
std::conditional<has_type<A>, A, identity<float>>::type::type; // float
std::conditional<has_type<B>, B, identity<float>>::type::type; // B
Раньше он использовался в качестве обходного пути для отсутствующего оператора области действия из decltype()
:
std::vector<int> v;
identity<decltype(v)>::type::value_type i;
// nowadays one can say just decltype(v)::value_type
identity
утилита предложено, чтобы быть добавлены к c++20:
namespace std {
template <typename T>
struct type_identity { using type = T; };
template <typename T>
using type_identity_t = typename type_identity<T>::type;
}
Он вводит невыводимый контекст при выводе аргументов шаблона из параметров функции. Например, скажем, у вас есть функция со следующей подписью:
template <class T>
void foo(T a, T b);
Если кто-то должен был вызвать foo(123L, 123)
, они получили бы ошибку замены, поскольку T
не может совпадать с long int
и int
в то же время.
Если вы хотите совместить только первый аргумент и при необходимости конвертировать другой, неявно, вы можете использовать identity
:
template <class T>
void foo(T a, typename identity<T>::type b);
Тогда b
не участвует в выводе типа, а foo(123L, 123)
разрешается до foo<long int>(123L, 123)
.