2015-10-21 2 views
1

Я хочу, чтобы функция lambda без апатии с переменным параметром списка параметров была рекурсивной. Но мне нужно стирать стили, чтобы избежать ошибок, таких как variable 'lambda' declared with 'auto' type cannot appear in its own initializer. В списке параметров шаблона Variadic требуется соответствующий функциональный объект для шаблона operator(). Для простой функции без стоянки я могу наложить ее на указатель на простую бесплатную старую функцию, но как добиться аналогичного для variadic функция без стоянки без гражданства? Я думаю, что я хочу автоматического типа вычета списка параметров шаблона (при конкретизации переменного шаблона: во время разговора или во время назначения): (псевдокод)Автоматический вывод параметров шаблона для шаблонов псевдонимов и классов шаблонов

#include <type_traits> 
#include <iostream> 

#include <cstdlib> 

template< typename first, typename second, typename ...rest > 
using fp = first (*)(first const &, second const &, rest const &...); // at least binary function 

int 
main() 
{ 
    template fp sum = [] (auto const & first, decltype(first) second, auto const &... rest) { return first + sum(second, rest...); }; 
    //   ^assignment                    ^call 
    std::cout << sum(1, 2.0, 3.0f) << std::endl; 
    return EXIT_SUCCESS; 
} 

Можно ли добиться такого поведения в настоящее время (C++ 14) (скажем, используя std::function или другой способ стирания типа)? Есть ли предложение по аналогичной языковой функции? Или, может быть, это полностью запрещено существующими языковыми правилами?

Другой возможный пример, где это будет полезно: (псевдокод)

template std::vector v{1, 2, 3}; 
static_assert(std::is_same< decltype(v), std::vector<int> >{}); 
+0

Вы можете разместить пример кода, который вызывает ошибку, Вы упоминаете 'переменная«лямбда»объявлена ​​с«авто» тип не может появиться в его собственном инициализаторе'? –

+0

@ м.с. 'auto lambda = [] (auto const & first, decltype (first) second, auto const & ... rest) {return first + lambda (second, rest ...); }; здесь переменная лямбда должна быть записана по умолчанию по значению (то же самое для '[&]' или '[& lambda]'). – Orient

+0

Для второго примера может быть [Выделение параметра шаблона для конструкторов (Rev. 3)] (http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2015/p0091r0.html) поможет , – cpplearner

ответ

3

Нет, нет никакого способа, чтобы сделать то, что вы хотите. Способ вывода результата выражения состоит в использовании auto. Нет способа вывести типы для шаблона функции или шаблона псевдонима. Рассмотрим простейший случай:

std::function<auto> if_this_existed = [](int x, int y) { return x + y; }; 

Вы, вероятно, ожидать std::function<int(int, int)>. Но std::function<void(int, int)> работает. Также std::function<long(long, long)>. На самом деле нечего вывести. Кроме того, для общих лямбды, это не имеет смысла, чтобы назначить тип конкретных:

std::function<void(???)> print = [](auto x) { std::cout << x; }; 

лямбда может быть вызвана с любым типом, что это версия для печати, но все, что мы вкладываем в ??? бы ограничить print быть именно этим типом. Так что это тоже не удается.

Так что, в конечном счете, нет, вы не можете рекурсивно писать свою общую вариационную лямбду. Хотя, sum было бы невозможно записать рекурсивно, так как вы не смогли бы написать базовый случай. Правильный способ написать такой общий sum() будет использовать складку выражение (C++ 1z):

auto sum = [] (auto const&... args) { 
    return (args + ...); 
}; 
+0

Действительно, корпус - мое упущение, но как насчет второго примера? – Orient

+0

@Orient Я не знаю, что означает ваш второй пример. – Barry

+0

Второй пример означает, что должен быть выведен первый параметр шаблона 'std :: vector', поэтому конструктор' std :: initializer_list' должен быть жизнеспособным. – Orient

Смежные вопросы