Reputation: 41
I'm learning C++20 concept/requires. I would like to implement a function for getting the sum of an integer list with template meta programming:
sum<IntList<1, 2, 3>>();
As it's known that C++ standards don't allow function partial specialization, I would like to use C++20 concept/requires to the similar stuff as function partial specialization.
Here is my code:
#include <iostream>
template<int...N>
class IntList;
template<int...N>
concept IsIntList = IntList<N...>{};
template<typename T>
int sum() {
return 0;
}
template<int...N>
requires IsIntList<N...>
int sum() {
return (N + ...);
}
int main() {
std::cout << sum<IntList<1, 2>>() << std::endl;
return 0;
}
But it could not produce what I want. Put my code in C++ Insights. The first sum
is instantiated, instead of the second sum
.
Here is the result of C++Insights:
#include <iostream>
template<int...N>
class IntList;
template<int...N>
concept IsIntList = IntList<N...>{};
template<typename T>
int sum() {
return 0;
}
/* First instantiated from: insights.cpp:21 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
int sum<IntList<1, 2> >()
{
return 0;
}
#endif
template<int...N>
requires IsIntList<N...>
int sum() {
return (N + ...);
}
int main()
{
std::cout.operator<<(sum<IntList<1, 2> >()).operator<<(std::endl);
return 0;
}
What's the correct way to solve this problem? Thanks!
Upvotes: 4
Views: 1212
Reputation: 42776
Your definition of the concept of IsIntList
is wrong, it only evaluates the value of IntList<N...>{}
, and since IntList
is not a bool
type, IsIntList
always return false.
You should use template partial specialization to define the IsIntList
.
template<int...N>
class IntList;
template<class T>
inline constexpr bool IsIntList = false;
template<int...N>
inline constexpr bool IsIntList<IntList<N...>> = true;
For a specialized version of the sum
, just constrain IsIntList<T>
to be true, then you can extract the value of the IntList
with the help of a tag class and template lambda to calculate the sum.
template<class>
struct tag{};
template<class T>
requires IsIntList<T>
int sum() {
return []<int...N>(tag<IntList<N...>>)
{ return (N + ... + 0); }(tag<T>{});
}
Upvotes: 0
Reputation: 473437
The central problem you're encountering is that you have a type template parameter whose type you want to be constrained to being some specialization of some template. That's not a thing you can do with a requires
clause. At least, not easily.
It's best to avoid this problem. You're only encountering it because you insist that sum
's template parameter must be some specialization of IntList
instead of the integers themselves directly. The best way to handle this is by ditching this assumption:
template<int... Ints>
constexpr int sum(IntList<Ints...>)
{ return (0 + ... + Ints); }
You then call this function as so: sum(IntList<1, 2>{})
. Note that IntList
needs to have a constexpr
default constructor.
Upvotes: 3