Можно ли сделать переменную шаблона в лямбда-сигнатуре универсальной?

Предположим, у вас есть функция, которая принимает 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::arrays можно использовать с лямбдой, аналогично второй версии 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>{} );

где мы используем значения в качестве параметров типа шаблона.

Другие вопросы по тегам