Я хотел написать несколько шаблонных функций для обработки типов определенным образом, поэтому я пришел к этим двум функциям. Первый берет объект и преобразует его со штамповкой в другой. Это гарантирует, что оба типа являются POD и имеют одинаковый размер. Второй был предназначен для того, чтобы просто взять любой указатель (как если бы void *), но все равно проверять, чтобы убедиться, что указатель относится к типу POD. Проблема, с которой я столкнулся, заключается в том, что если я передам неконстантный указатель, то вместо этого будет использоваться первая функция. Что было бы лучшим способом справиться с этим?
template <class TO, class FROM>
FORCE_INLINE TO punning_cast(const FROM &input)
{
static_assert(std::is_pod<TO>::value, "TO must be POD");
static_assert(std::is_pod<FROM>::value, "FROM must be POD");
static_assert(sizeof(TO) == sizeof(FROM), "TO and FROM must be the same size");
TO out;
std::memcpy(&out, &input, sizeof(TO));
return out;
}
template <class TO, class FROM>
FORCE_INLINE TO punning_cast(const FROM *input)
{
static_assert(std::is_pod<TO>::value, "TO must be POD");
static_assert(std::is_pod<FROM>::value, "FROM must be POD");
TO out;
std::memcpy(&out, input, sizeof(TO));
return out;
}
Шаблоны функций смешивать странно с перегрузкой.
Возможное решение (не уникальное) будет использовать enable_if
для объявления каждой функции, кодирующей вторую для типов указателей, и наоборот для первой
#include <type_traits>
template <class TO, class FROM>
FORCE_INLINE typename enable_if<!is_pointer<FROM>::value, TO>::type
punning_cast(const FROM &input) { ... }
template <class TO, class FROM>
FORCE_INLINE typename enable_if<is_pointer<FROM>::value, TO>::type
punning_cast(const FROM input) { ... }
Таким образом, примером достижения устранения неоднозначности (между ссылкой и указателем) будет этот
Отказ от ответственности: мне нравится Никос Атанасиу ответ лучше для C ++ 11 и далее.
Одним из решений этой (общей) проблемы является обертывание функций в структуры и добавление вспомогательной функции, которая выбирает одну из них:
template <class TO, class FROM>
struct punning_cast_impl
{
static FORCE_INLINE TO cast(const FROM &input)
{
static_assert(std::is_pod<TO>::value, "TO must be POD");
static_assert(std::is_pod<FROM>::value, "FROM must be POD");
static_assert(sizeof(TO) == sizeof(FROM), "TO and FROM must be the same size");
TO out;
std::memcpy(&out, &input, sizeof(TO));
return out;
}
};
template <class TO, class FROM>
struct punning_cast_impl<TO, FROM*>
{
static FORCE_INLINE TO cast(const FROM *input)
{
static_assert(std::is_pod<TO>::value, "TO must be POD");
static_assert(std::is_pod<FROM>::value, "FROM must be POD");
TO out;
std::memcpy(&out, input, sizeof(TO));
return out;
}
};
template<class TO, class FROM>
TO FORCE_INLINE punning_cast(const FROM& input)
{
return punning_cast_impl<TO, FROM>::cast(input);
}
int main()
{
double d1 = 50.0;
int64_t i1 = punning_cast<int64_t>(d1); // calls version #1
double d2 = 100.0;
int64_t i2 = punning_cast<int64_t>(&d2); // calls version #2
}