-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Properly convert constants to CharType #1315
Conversation
+1 |
Actually: do you think there should be some comments in this code to just link to this Issue or the SO post that explains why it's necessary? I suppose you could get some of that via GitHub, but that might get buried? very minor thing you can ignore. |
@nlohmann That's it. Except if you are using it with signed chars (like 'l') then for the sake of micro optimization we could add some overload like template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >
static constexpr CharType to_char_type(char x) noexcept
{
return x;
} Idk if it is so necessary tho. @jaredgrubb I think that with some bit shift magic this could be done in less obvious but more compact style. But I prefer straightforward |
@oktonion The code you propose has the signature |
@nlohmann my bad, there is a working example: // Example program (I removed constexpr for the sake of std::cout calls)
#include <iostream>
#include <string>
#include <cstring>
template<bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_signed<char>::value > * = nullptr >
static CharType to_char_type(std::uint8_t x) noexcept
{
std::cout << "1" << std::endl;
return *reinterpret_cast<char*>(&x);
}
template < typename C = CharType,
enable_if_t < std::is_signed<C>::value and std::is_unsigned<char>::value > * = nullptr >
static CharType to_char_type(std::uint8_t x) noexcept
{
std::cout << "2" << std::endl;
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
static_assert(std::is_pod<CharType>::value, "CharType must be POD");
CharType result;
std::memcpy(&result, &x, sizeof(x));
return result;
}
template<typename C = CharType,
enable_if_t<std::is_unsigned<C>::value>* = nullptr>
static CharType to_char_type(std::uint8_t x) noexcept
{
std::cout << "3" << std::endl;
return x;
}
template < typename InputCharType,
typename C = CharType,
enable_if_t <
std::is_signed<C>::value and
std::is_signed<char>::value and
std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
> * = nullptr >
static CharType to_char_type(InputCharType x) noexcept
{
std::cout << "4" << std::endl;
return x;
}
int main()
{
to_char_type(0x08);
to_char_type(-23);
to_char_type(254);
to_char_type('l');
}
so for
for
the '4' is faster than '1' and more clear for compiler optimizer. It's micro optimization though. |
If you really want to stress-test your implementation, make sure to try all three |
Thanks everyone! |
Fixes #1286.