2016-12-31 8 views
2

私は、次のようなではなく、テンプレートの構文ではなくラムダ構文で汎用のSUM関数を書きたかった: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

これはあなたが必要とする単純な理由のために動作しません:あなたは与えられたパラメータは、算術型のすべてのある場で検証したい場合は、次のように

は、あなたはブールトリックを使用することができますエンドケースをカバーするための専門化。少なくとも2つのラムダが必要です。 –

+1

最近、C++がどこに向かうのが好きではありません。 –

+0

@Sam Varshavichik:2つのラムダを使ってどうやって行くのですか? –

答えて

4

C++ 14では、ジェネリックlambdaを使って再帰を行う必要はありません。例として
、あなたはこれを行うことができます。

#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)...}を説明してください。 (void)_;やってる? –

+0

@KitFisto一時配列を作成します(直後に破棄)。このステートメントの目的は 'values'を解凍し、' ret'でそれらを合計することです。 C++ 17まではうまくできません。残念です。 – skypjack

+0

(ret + = values)はどのように許されていますか?折り畳み操作のように見えます。 –

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

これをlambdaで実装できない理由は、一度特定のパラメータセットでラムダを呼び出すことです。コンパイラは、そのパラメータセットに一致するファンクションコール演算子を持つファンクタライクなクラスを生成します。したがって、同じラムダを同じセットのパラメータを渡すことなく、それ自体の内側からでもどこからでも呼び出すことはできません。したがって、パラメータパックからパラメータをポップするのを防ぎます。 –

関連する問題