2016-11-25 11 views
2

このコードをコンパイルする際に問題があります。Variadicクラステンプレート

私がやろうとしているのは、渡されるすべての要素の合計を与えることができるvariadicクラステンプレートを作成することです(例えば、1,2,3,4,5,6は21を与えるべきです)。それはintまたはfloat。私は基本的に2つの関数テンプレートを使って再帰的にそれを行うことができますが、私は答えを正しく得ていますが、クラスでそれを実装しているときには答えが出ません。

template <typename T> 
class Myclass 
{ 
public: 

    T sum; 

    T func(T A,T... B) 
    { 
     sum+=A; 
     func(B...); 
    } 

    T func(T A) 
    { 
     sum+=A; 
     return sum; 
    } 
}; 


int main() 
{ 
    Myclass<int> myclass; 
    cout<<myclass.func(12,11,11,23); 

    return 0; 
} 
+0

あなたの第一の方法は、 'T'を返しません。 –

答えて

3

あなたのコードdoes not compileTがパラメータパックではないようT...は、無効な可変長引数の拡張であるため。

あなたのコードには、他にもいくつかの問題があります。 TRest...にマッチした値は、どのようなタイプのものとすることができるという

template <typename T> 
class Myclass 
{ 
public: 
    // `sum` needs to be initialized to a value, otherwise its value 
    // will be undefined. 
    T sum = 0; 

    // `TRest...` is a template variadic type pack. 
    template <typename... TRest> 
    T func(T A, TRest... B) 
    { 
     sum+=A; 

     // You need to return from the recursive case of `func`. 
     return func(B...); 
    } 

    T func(T A) 
    { 
     sum+=A; 
     return sum; 
    } 
}; 

working wandbox example


注:私は、以下のスニペットでそれらに対処します。あなたがTことを強制したい場合は、次のような技術(またはstatic_assert使用することができます。

template <typename...> 
using force_to_t = T; 

// ... 

T func(T A, force_to_t<TRest>... B) 
{ 
    sum+=A; 

    // You need to return from the recursive case of `func`. 
    return func(B...); 
} 

を私は別の質問に感謝to Piotr's answerこのソリューションを学びました。

+0

funcを複数回呼び出すことは、やはり問題になります。別のcoutを追加する<< myclass.func(12,11,11,23);その例に – stijn

+0

その 'force_to_t'は素晴らしいトリックです!何か新しいもの(と非常に便利!)。 – Angew

3
T func(T A,T... B) 
{ 
    sum+=A; 
    func(B...); 

} 

funcTそのテンプレートパラメータパックを持つ関数テンプレートでない場合、これは有効なC++構文ではありません。 ...は、パックの展開にのみ使用できます。 Tは、クラステンプレートの非パックテンプレートパラメータです。

達成する方法に応じて、これを行うには2通りの方法があります。

ワン:

template <typename T> 
class Myclass 
{ 

public: 

    T sum; 

    template <class F1, class... F> 
    T func(F1 A, F... B) 
    { 
     sum+=A; 
     func(B...); 
     return sum; 
    } 

    template <class F> 
    T func(F A) 
    { 
     sum+=A; 
     return sum; 
    } 

}; 

二:あなたはfuncは、任意の種類のミックスを受け入れる場合、あなたはそれ(メンバー)関数テンプレートにすることができますが、funcだけT Sを受け入れるようにしたい場合は、することができます初期化リストを使用するように変更します。これは例えばfunc({1, 2, 42})代わりのfunc(1, 2, 42)(括弧内のリストでそれを呼び出す必要がありますが、それはまた、例えばで撮影したアプローチだと

template <typename T> 
class Myclass 
{ 

public: 

    T sum; 

    T func(std::initializer_list<T> A) 
    { 
     for (const auto& a : A) 
      sum+=a; 
     return sum; 
    } 

}; 

注意を。


手元の質問とは無関係に、コードにいくつかの問題があることに注意してください。

上記の例で修正した1つは、funcの最初のオーバーロードが何も返されなかったということです。これを呼び出すと、未定義の動作が発生します。

@Zeregesがコメントで指摘している別の1つは、T sumが明示的に初期化されていないということです。MyClassがPODタイプ(intまたはdoubleなど)でインスタンス化されている場合は、初期化されずに使用されます。あなたはMyclassのコンストラクタを追加する必要があります

Myclass() : sum{} {} 
+0

コードに2番目の問題があります。 'T sum;'は宣言であり、TがPOD型の場合、正しく初期化されません。 – Zereges

+0

@Zeregesはい、本当にありがとうございます。おそらく実際のコードには質問から省略されたctorが含まれていますか? – Angew

0

あなたは再帰呼び出しを避けるため別のアプローチでそれを行うことができます。

template <typename T> 
class Myclass 
{ 
public: 
    T sum; 

    Myclass() { sum = 0; } 

    template<typename ...T1> 
    T func(T1 ... args) 
    { 
     auto l_expansion_list = 
     { 
      (
       [this, &args]() 
       { 
        this->sum += args; 
        return true; 
       }() 
      )... 
     }; 

     return sum; 
    } 
}; 
0

あなたはstd::initializer_listためのイニシャライザとしてシーケンシャルsum+=Aを書き込むことによって、再帰呼び出しの必要性を回避することができます

template <typename T> 
class Myclass 
{ 
    template <class... F> 
    T func_impl(F... A) 
    { 
     std::initializer_list<int>{ 
      ((void)(sum+=A), 0)...}; 
     return sum; 
    } 
public: 
    Myclass() :sum(){} 
    T sum; 
    template <class F1, class... F> 
    T func(F1 A, F... B) 
    { 
     return func_impl(A, B...); 
    } 
}; 
関連する問題