2

I have a problem compiling this code.

All I am trying to do is create a variadic class template that can give me the sum of all elements that are passed in (eg. 1,2,3,4,5,6 should give 21) whether it's int or float. I could basically do it with two function templates recursively for which I'm getting the answer correctly but when I'm implementing it in class it doesn't give me an answer.

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;
}
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
Subham Dubey
  • 60
  • 1
  • 7

4 Answers4

3

Your code does not compile because T... is an invalid variadic expansion, as T is not a parameter pack.

You code has also several other issues. I will address them in the snippet below:

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


Note that the values matched in TRest... can be of any type. If you want to force them to be T, you can use the following technique (or 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...);
}

I learned this solution thanks to Piotr's answer on another question.

Community
  • 1
  • 1
Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
3
T func(T A,T... B)
{
    sum+=A;
    func(B...);

}

This is not valid C++ syntax when func is not a function template with T its template parameter pack. ... can only be used to expand packs; T is a non-pack template parameter of the class template.

There are two ways to do this, depending on what you want to achieve.

One: If you want func to accept a mix of arbitrary types, you can make it a (member) function template:

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

};

Two: If you want func to only accept Ts, you can change it to use an initializer list:

template <typename T>
class Myclass
{

public:

    T sum;

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

};

Note that this will require calling it with a list in braces (e.g. func({1, 2, 42}) instead of func(1, 2, 42), but it's the approach also taken by e.g. std::max.


Notice that there are a few issues in your code unrelated to the question at hand.

One, which I fixed in the example above, is that your first overload of func didn't return anything. Calling it would result in Undefined Behaviour.

Another one, pointed out by @Zereges in the comments, is that T sum is not initialised explicitly. If MyClass is instantiated with a POD type (such as int or double), it will be used uninitialised. You should add a constructor for Myclass:

Myclass() : sum{} {}
Community
  • 1
  • 1
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
1

You can avoid the need for recursive calls by writing the sequential sum+=A as an initialiser for a std::initializer_list:

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...);
    }
};
Mankarse
  • 39,818
  • 11
  • 97
  • 141
0

You can do that with another approach that avoid recursive call.

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;
    }
};
MRB
  • 3,752
  • 4
  • 30
  • 44