Reputation: 631
I need to compute the product of a bunch of numbers at compile time passed to a templated struct. I succeeded to make an ugly solution :
template<std::size_t n1, std::size_t ...args>
struct mul_all
{
static constexpr std::size_t value = n1 * mul_all<args...>;
};
template<>
struct mul_all<0>
{
static constexpr std::size_t value = 1;
};
The problem is that each time I have to feed 0 to template args to my struct like so
int main()
{
std::cout << mul_all<1,2,5,4,5,7,0>::value << " "
<< mul_all<4,2,0>::value;
return 0;
}
is there any workaround to get read of that last zero?
note: I am a beginner in TMP.
Upvotes: 6
Views: 478
Reputation: 154045
The C++17 approach make that nice and simple:
template <std::size_t... A>
constexpr std::size_t mul = (A * ... * std::size_t(1u));
int main() {
constexpr std::size_t val = mul<1, 2, 3, 4>;
}
For existing C++ versions you'll need to partially specialize the case mul<v>
:
template <std::size_t... V> struct mul;
template <std::size_t V> struct mul {
statuc constexpr std::size_t value = V;
};
template <std::size_t V, std::size_t... T> struct mul {
statuc constexpr std::size_t value = V * mul<T...>::value;
};
template <std::size_t... V>
using mul_v = mul<V...>::value;
int main() {
constexpr std::size_t v = mul_v<1, 2, 3, 4>;
}
Upvotes: 2
Reputation: 218323
In C++17, with folding expression, you may directly do
template<std::size_t ...args>
struct mul_all
{
static constexpr std::size_t value = (args * ...);
};
Before, you have to do the partial specialization:
template<std::size_t n1, std::size_t ...args>
struct mul_all
{
static constexpr std::size_t value = n1 * mul_all<args...>::value;
};
template<std::size_t n>
struct mul_all<n>
{
static constexpr std::size_t value = n;
};
Upvotes: 6
Reputation: 360
You need to replace your specialization with:
template<std::size_t n1, std::size_t ...args>
struct mul_all
{
static constexpr std::size_t value = n1 * mul_all<args...>::value;
};
template<std::size_t n>
struct mul_all<n>
{
static constexpr std::size_t value = n;
};
Upvotes: 5
Reputation: 75924
One way is to specialize for empty varargs. For that you need the main template to be variadic args only:
// main template never used
template<std::size_t ...args> struct mul_all
{
};
// specialization for at least one arg
template<std::size_t n1, std::size_t ...args>
struct mul_all<n1, args...>
{
static constexpr std::size_t value = n1 * mul_all<args...>::value;
};
// specialization for empty args
template<>
struct mul_all<>
{
static constexpr std::size_t value = 1;
};
So now you can do:
mul_all<1, 2, 3>::value;
Upvotes: 3