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

Предположим, у вас есть функция, которая принимает 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 ]

0 голосов
/ 21 октября 2018

Есть ли способ ввести аналогичное выведенное значение в лямбда-выражение, чтобы с этим лямбда можно было использовать любые 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).

0 голосов
/ 21 октября 2018

Ваш синтаксис vector<auto> неверен.

Вы можете разделить тип параметра auto в типе / теле возвращаемого значения лямбда-выражения, используя вспомогательные функции и классы признаков.

\ http://www.open -std.org / jtc1 / sc22 / wg21 / docs /apers / 2017 / p0428r1.pdf - это предложение добавить []<template T>( std::vector<T>& ){} к языку.Примерно так должно быть в .

Я уже делал двойные лямбды раньше:

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>{} );

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

0 голосов
/ 21 октября 2018

Вы можете использовать некоторые специальные свойства типа:

#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
}

онлайн-компилятор

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...