Можно ли сделать переменную шаблона в лямбда-сигнатуре универсальной?
Предположим, у вас есть функция, которая принимает std::vector
любого типа и обрабатывает его некоторым образом:
template<typename T>
void foo(std::vector<T> &vec) {
// work with vec
}
поскольку C++14
мы можем достичь того же самого с лямбдами. В этом случае мы называем их общими лямбдами, поскольку мы вводим для них шаблонный вывод:
auto foo_lambda = [](std::vector<auto> &vec) {
// work with vec
};
Но наши возможности кажутся мне довольно ограниченными. Предположим, что мне нужно не только ввести вывод типа, но и ввести значения шаблонов. Например, давайте изменим std::vector
в std::array
:
template<typename T, std::size_t size>
void foo(std::array<T, size> &arr) {
// work with arr
}
При работе с шаблонными функциями мы можем ввести значение шаблона, которое можно использовать для соответствия потребностям аргумента. Ухоженная.
Я хотел достичь той же функциональности с помощью общих лямбд, но я не смог этого сделать.
Есть ли способ ввести подобное, выведенное значение в лямбда-выражение, чтобы любой std::array
s можно использовать с лямбдой, аналогично второй версии foo()
функция выше?
РЕДАКТИРОВАТЬ: Как указано в комментариях Evg, мой vector<auto>
синтаксис нестандартного расширения GCC. Подробнее см. Этот ответ со ссылкой на этот документ.
3 ответа
Вы можете использовать некоторую специальную черту типа:
#include <type_traits>
#include <utility>
#include <array>
template<typename x_Whatever> struct
is_array: ::std::false_type {};
template<typename x_Item, ::std::size_t x_items_count> struct
is_array<::std::array<x_Item, x_items_count>>: ::std::true_type {};
int main()
{
auto Do_SomethingWithArray
{
[](auto & should_be_array)
{
static_assert
(
is_array
<
::std::remove_reference_t<decltype(should_be_array)>
>::value
);
}
};
::std::array<int, 3> a{};
Do_SomethingWithArray(a); // Ok
int x{};
Do_SomethingWithArray(x); // error
}
Есть ли способ ввести подобное выведенное значение в лямбда-выражение, чтобы с указанной лямбдой можно было использовать любые std::arrays, аналогично второй версии функции foo(), описанной выше?
Да. Но, к сожалению, начиная (предположительно) с C++20
auto foo_lambda = []<typename T, std::size_t S>(std::array<T, S> & arr)
{ /* ... */ };
В C++14/C++17 вы можете использовать decltype()
чтобы извлечь то, что вам нужно.
в std::array
случай, что-то как
auto foo_lambda = [](auto & arr)
{
using T = typename std::remove_reference_t<decltype(arr)>::value_type;
std::size_t S = arr.size();
// ...
};
С другими типами вы можете разрабатывать индивидуальные черты типа для извлечения необходимых элементов, начиная с decltype(arr)
,
Ваш vector<auto>
синтаксис неверен.
Вы можете разорвать на части тип auto
параметр в возвращаемом типе / теле лямбды с использованием вспомогательных функций и классов признаков.
\ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0428r1.pdf - это предложение о добавлении []<template T>( std::vector<T>& ){}
на язык. Примерно так должно быть в с ++ 20.
Я сделал двойные лямбды раньше:
template<class T>struct tag_t{using type=T;};
template<class T>constexpr tag_t<T> tag{};
template<class Tag>using type_t=typename Tag::type;
auto f = [](auto tag_T){ return []( std::vector<type_t<decltype(tag_T)>> const& v){ /* code */ }; };
и использовать как:
f(tag<int>)( std::vector<int>{} );
где мы используем значения в качестве параметров типа шаблона.