问题
Here is an example of problem: a constant variable's template should expand its type based on parameters. While direct way is possible, by giving size of type, or underlying typename, it's error-prone.
#include <iostream>
template<size_t bit>
constexpr const uint16_t BIT = 1 << bit;
template<size_t... bits>
constexpr const uint16_t BITS = (uint16_t(1 << bits)|...);
int main()
{
std::cout << BITS<0,1,3,12> << std::endl;
}
Idea is to implement template data type which would return type
which is unsigned integer at least of size of greatest value in parameter pack. This also would allow to check if template arguments are sane.
回答1:
Pretty straight forward in C++17. The maximum value we can calculate with a simple invocation of std::max
(the initializer list overload is constexpr since C++14).
The result we'll need to plug into a utility that maps sizes to integer types, but that's fairly simple to write now:
template<std::size_t N>
struct size2Type {
static auto type_calculator() {
static_assert( N < 64 );
if constexpr ( N < 8 )
return uint8_t{};
else if constexpr ( N < 16 )
return uint16_t{};
else if constexpr ( N < 32 )
return uint32_t{};
else
return uint64_t{};
}
using type = decltype(type_calculator());
};
Then, putting it to use in your original example:
template<size_t bit>
constexpr typename size2Type<bit>::type BIT = (typename size2Type<bit>::type)(1) << bit;
template<size_t... bits>
constexpr typename size2Type<std::max({std::size_t(0), bits...})>::type BITS = (BIT<bits> | ... | 0);
I didn't prettify the cast, but a utility can be written to accomplish that too.
You can see it live.
回答2:
template<std::size_t bits>
class uint_that_has_bits_helper {
static auto calculator() {
// conditionally compile lines based on compiler capabilities:
if constexpr (bits <= 8) return std::uint8_t{};
else if constexpr (bits <= 16) return std::uint16_t{};
else if constexpr (bits <= 32) return std::uint32_t{};
else if constexpr (bits <= 64) return std::uint64_t{};
else if constexpr (bits <= 128) return std::uint128_t{};
}
public:
using type = declype(calculator());
};
template<std::size_t bits>
using uint_that_has_bits = typename uint_that_has_bits<bits>::type;
template<std::size_t index>
constexpr auto bit = uint_that_has_bits<index+1>(1) << uint_that_has_bits<index+1>(index);
now we can get:
template<std::size_t... index>
constexpr const auto bits = static_cast<uint_that_has_bits< std::max({index...})+1>>(bit<index> | ...);
来源:https://stackoverflow.com/questions/57644896/how-to-find-maximum-value-in-parameter-pack