I'm trying to write a type trait for detecting if, given a type K
, I can call static_cast
on variables of this type K
(or reference to K
) to uint32_t
or not.
This is what I'm arriving at, but can't seem to make it work.
template <typename K, typename Whatever = void> struct ConvertibleToUint32 {
static constexpr bool value = false;
};
template <typename K>
struct ConvertibleToUint32<K, decltype(static_cast<uint32_t>(std::declval<K>()))> {
static constexpr bool value = true;
};
I have also tried using std::is_convertible, but doesn't seem to work here.
Here's a paste with a run - https://wandbox.org/permlink/iuP99PNAVIYhh208
The specialization doesn't seem to get hit.
Here's the full test program -
#include <iostream>
#include <stdint.h>
template <typename K, typename Whatever = void> struct ConvertibleToUint32 {
static constexpr bool value = false;
};
template <typename K>
struct ConvertibleToUint32<K, decltype(static_cast<uint32_t>(std::declval<K>()))> {
static constexpr bool value = true;
};
struct A {
explicit operator uint32_t() const { return 1; }
};
struct B {
};
int main()
{
std::cout << ConvertibleToUint32<A>::value << "\n";
std::cout << ConvertibleToUint32<B>::value << "\n";
std::cout << std::is_convertible<A, uint32_t>::value << "\n";
}
The static_cast operator converts variable j to type float . This allows the compiler to generate a division with an answer of type float . All static_cast operators resolve at compile time and do not remove any const or volatile modifiers.
It helps maintain correctness, since static_cast cannot do some casts which a C-style cast can. This helps if you make a mistake about some of the types involved, perhaps handling a pointer while being convinced it's an integer (and down several layers of templates and typedefs, that's not too difficult to imagine).
Static casts are only available in C++. Static casts can be used to convert one type into another, but should not be used for to cast away const-ness or to cast between non-pointer and pointer types.
static_cast<void>() is the 'C++ way' of writing void conversion. In the en.cppreference.com website mentioned as discards the value of the expression.
It doesen't get hit because decltype(static_cast<uint32_t>(std::declval<K>()))
is not void
, so it's not a more specialized version of the primary template for the argument Whatever=void
.
The fix is fairly easy
template <typename K>
struct ConvertibleToUint32<K, decltype(static_cast<uint32_t>(std::declval<K>()), void())> {
static constexpr bool value = true;
};
The second argument matches the default, and will therefore be picked up in partial ordering. Alternatively, you can just specify a default of Whatever=uint32_t
and get the same effect. void
is just what the general idiom employs.
template <typename K, typename Whatever = uint32_t>
struct ConvertibleToUint32 {
static constexpr bool value = false;
};
As an aside, I suggest you start favoring the cstdint
header and its std::uint32_t
alias. Same net effect usually, but the use of the C++ version is generally preferable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With