Reputation: 29962
Suppose that I want to create a general system which can store variable-width integers together. In this system, we can use an enum
, which contain member names (this enum members have consecutive values [0;count)
):
enum class Group1 {
AttrA,
AttrB,
AttrC,
};
I add inline constexpr
specialization, which tells, how many members are there:
template <typename TYPE>
inline constexpr int count = -1;
template <>
inline constexpr int count<Group1> = 3; // Group1 has 3 members (AttrA/B/C)
And I add inline constexpr
specializations which describes each members width:
template <auto VALUE>
inline constexpr int nBits = -1;
template <>
inline constexpr int nBits<Group1::AttrA> = 3; // AttrA need 3 bits of storage
template <>
inline constexpr int nBits<Group1::AttrB> = 2;
template <>
inline constexpr int nBits<Group1::AttrC> = 4;
Now, I'd like to have a general constexpr
function , which can calculate summed width (of any type, not just Group1
):
template <typename TYPE>
constexpr int summedWidth() {
int r = 0;
for (int i=0; i<count<TYPE>; i++) {
r += nBits<static_cast<TYPE>(i)>;
}
return r;
}
However, this doesn't compile, because of the r += nBits...
line:
error: non-type template argument is not a constant expression
Is it possible to create a compilable summedWidth()
function (or any other solution, which provides a compile-time constant)?
Upvotes: 3
Views: 679
Reputation: 119184
Use std::make_integer_sequence
to expand count<TYPE>
into a pack that you can fold over:
template <typename TYPE, int... ints>
constexpr int summedWidthHelper(std::integer_sequence<int, ints...>) {
return (0 + ... + nBits<static_cast<TYPE>(ints)>);
}
template <typename TYPE>
constexpr int summedWidth() {
return summedWidthHelper<TYPE>(std::make_integer_sequence<int, count<TYPE>>{});
}
Coliru link: http://coliru.stacked-crooked.com/a/28df4b17d071f6e5
Upvotes: 2