2016-12-31 7 views
2

Я хотел написать обобщенную функцию суммы, как следующий один, но не в синтаксисе шаблона, но в синтаксисе лямбда:Как рассчитать сумму с использованием вариабельной общей лямбды в C++?

template<typename T> 
auto Sum(T lastSummand) 
{ 
    return lastSummand; 
} 

template<typename T, typename... Ts> 
auto Sum(T firstSummand, Ts... restSummands) 
{ 
    return firstSummand + Sum(restSummands...); 
} 

Поскольку общие лямбды сопоставляются с шаблонами должно быть возможно сделать что-то вроде:

auto sum = [](auto firstSummand, auto... restSummands) { ... }; 

Но я не могу понять, как сделать рекурсию с помощью лямбда. Поиск в этом и других местах не привел многого.

+0

Это не будет работать по той простой причине, что вам нужно специализация для покрытия конечного случая. Вам нужно как минимум два лямбда. –

+1

Мне не нравится, когда C++ собирается в эти дни. –

+0

@Sam Varshavichik: Как бы вы это сделали, используя две лямбды? –

ответ

4

В C++ 14 вам не нужна рекурсия, чтобы сделать это с помощью общих лямбда.
В качестве примера, вы можете сделать это:

#include<type_traits> 
#include<iostream> 

int main() { 
    auto l = [](auto... values) { 
     std::common_type_t<decltype(values)...> ret = {}; 
     decltype(ret) _[] = { (ret += values)... }; 
     (void)_; 
     return ret; 
    }; 

    auto v = l(0, 0., 5, 4.2); 
    std::cout << v << std::endl; 
} 

возвращаемый тип задается std::common_type_t данного пакета.
Остальная часть кода содержит общий шаблон, обычно используемый при ожидании сгибающих выражений.

В C++ 17 станет:

#include<iostream> 

int main() { 
    auto l = [](auto... values) { return (values + ...); }; 
    auto v = l(0, 0., 5, 4.2); 
    std::cout << v << std::endl; 
} 

Посмотри на wandbox.

Если вы хотите проверить на лета, что данные параметры являются всеми арифметическими типами, вы можете использовать Ий трюк, как это следующим образом:

auto l = [](auto... values) { 
    static_assert(
     std::is_same< 
      std::integer_sequence<bool, true, std::is_arithmetic<decltype(values)>::value...>, 
      std::integer_sequence<bool, std::is_arithmetic<decltype(values)>::value..., true> 
     >::value, "!" 
    ); 

    std::common_type_t<decltype(values)...> ret = {}; 
    decltype(ret) _[] = { (ret += values)... }; 
    (void)_; 
    return ret; 
}; 
+0

Не могли бы вы объяснить, что decltype (ret) _ [] = {(ret + = values) ...}; (Пустоты) _; делается? –

+0

@KitFisto Создает временный массив (который должен быть немедленно отброшен). Цель этого заявления - распаковать 'values' и суммировать их в' ret'. Вы не можете сделать это изящно, пока C++ 17, извините. – skypjack

+0

И как (ret + = значения) ... разрешено? Он почти выглядит как оператор сгиба. –

0

Ну, я предполагаю, что вам нужен функторный тип, чтобы рассчитать сумму, если вы используете лямбда. Если это так, я полагаю, вы могли бы написать небольшой родовой класс, чтобы занять место этой лямбда.

template < typename T > struct Sum 
{ 
    template < typename U > 
    T operator() (U v) const noexcept 
    { 
     return static_cast<T>(v); 
    } 

    template < typename U, typename... Values > 
    T operator() (U v, Values&&... vs) const noexcept 
    { 
     return static_cast<T>(v) + (*this)(std::forward<Values>(vs)...); 
    } 
}; 

и используются как:

auto sum = Sum<int>(); 
printf("%d\n", sum(23, 4.0, true, 7)); 

Я написал это таким образом, что тип возвращаемого значения может быть определен заранее. Но я полагаю, вы могли бы настроить его, чтобы сделать этот общий.

Если это было не ваше намерение, пожалуйста, проигнорируйте этот ответ.

+1

Спасибо за ваш ответ. Сама цель моего вопроса заключалась в том, как это сделать без явного использования шаблонов. –

+0

Причина, по которой это невозможно реализовать с помощью лямбда, заключается в том, что как только вы вызываете лямбду с определенным набором параметров. Компилятор генерирует класс, подобный функтору, с оператором вызова функции, соответствующим этому набору параметров. Поэтому вы не можете вызывать одну и ту же лямбду внутри себя или где-либо еще, не передавая один и тот же набор параметров. Таким образом, вы не сможете добавлять параметры из пакета параметров. –

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

  • Нет связанных вопросов^_^