0

I have a class like this:

template<std::size_t T, std::size_t... Args>
class A{
   public:
      std::array<int,summation<Args...>::value> x;
}

where summation is defined as:

template<std::size_t size, std::size_t... sizes>
    struct summation
    {
        static const std::size_t value = size + summation<sizes...>::value;
    };


template<std::size_t size>
    struct summation<size>
    {
        static const std::size_t value = size;
    };

The problem is that when Args is empty (i.e., I only specify the T template) the base case does not work and I get a compilation error message:

error: wrong number of template arguments (0, should be 1 or more)

How can I modify the recursion of summation to also properly handle the case when sizeof...(Args)==0 and return a value of 0 for the summation in this case? I am using C++11. Thanks

NOTE: I would also like this to work in a multithreaded environment, where summation can be simultaneously invoked by different threads with different parameters. What changes would be needed for this to work in a multithreaded environment? Thanks

astrophobia
  • 839
  • 6
  • 13

2 Answers2

4

The declaration should be the most generic one and then you can partially specialize with possible cases. Below solution works: https://godbolt.org/z/Ye7xEJ

template<std::size_t... sizes>
    struct summation;

template<std::size_t size, std::size_t... sizes>
    struct summation<size, sizes...>
    {
        static const std::size_t value = size + summation<sizes...>::value;
    };

template<>
struct summation<> {
    static const std::size_t value = 0;
};

std::size_t foo() {
    return summation<1,3,4>::value;
}

std::size_t foo2() {
    return summation<>::value;
}
balki
  • 26,394
  • 30
  • 105
  • 151
  • it works thanks. I do not understand why the declaration is needed though. Without the declaration (first 2 lines) I get a compilation error: "summation is not a class template struct summation" – astrophobia Oct 22 '18 at 04:11
  • Works but... adding the specialization with zero sizes, the specialization with exactly one size become superfluous: you can delete it and his works is made by the one-or-more sizes specialization. Another suggestion: the question is tagged C++11 so you can define `constexpr`, instead of simply cost, the `value`s – max66 Oct 22 '18 at 09:14
  • @astrophobia - Is needed because you originally defined a `summation` with one or more sizes and the main version manage the more case where the specialization manage the only-one case. Now, in the Balki's solution, `summation` manage zero or more sizes (because you asked for the zero case); so the one -or-more can't be anymore the main case (can't manage the zero case) and Balki has written is as a specialization. Now you have three specializations (one or more, exactly one and exactly zero sizes) but no definition. The first two lines now are the definition (no implementation). – max66 Oct 22 '18 at 09:23
  • @max66 Thanks. Updated. Yes, one size becomes superfluous. – balki Oct 22 '18 at 10:42
  • However what if the code is multithreaded and we are trying to calculate multiple summations in parallel? Would this still work? I notice many static variables are used in this solution – astrophobia Oct 22 '18 at 23:19
  • @astrophobia templates are compile time features. All of this is evaluated in compile time. – balki Oct 22 '18 at 23:52
1

This code:

size + summation<sizes...>::value;

translates

summation<1,2,3,4>::value

into

1 + summation<2, 3, 4>::value;  // Trims out first parameter; matches variadic version

2 + summation<3, 4>::value;    // Again, trims out first parameter;matches variadic version

3 + summation<4>::value;  // Matches <size> version. You support signature up-to this point

4 + summation<>::value;   // summation<> definition is missing in your code!!

More detailed explanation here. https://stackoverflow.com/a/48003232/1465553

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79