Skip to content

Commit 221fb1e

Browse files
DennisOSRMjagerman
authored andcommitted
Untangle cast logic to not implicitly require castability (#1442)
The current code requires implicitly that integral types are cast-able to floating point. In case of strongly-typed integrals (e.g. as explained at http://www.ilikebigbits.com/blog/2014/5/6/type-safe-identifiers-in-c) this is not always the case. This commit uses SFINAE to move the numeric conversions into separate `cast()` implementations to avoid the issue.
1 parent 534b756 commit 221fb1e

File tree

1 file changed

+29
-15
lines changed

1 file changed

+29
-15
lines changed

include/pybind11/cast.h

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <array>
1818
#include <limits>
1919
#include <tuple>
20+
#include <type_traits>
2021

2122
#if defined(PYBIND11_CPP17)
2223
# if defined(__has_include)
@@ -1009,21 +1010,34 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
10091010
return true;
10101011
}
10111012

1012-
static handle cast(T src, return_value_policy /* policy */, handle /* parent */) {
1013-
if (std::is_floating_point<T>::value) {
1014-
return PyFloat_FromDouble((double) src);
1015-
} else if (sizeof(T) <= sizeof(ssize_t)) {
1016-
// This returns a long automatically if needed
1017-
if (std::is_signed<T>::value)
1018-
return PYBIND11_LONG_FROM_SIGNED(src);
1019-
else
1020-
return PYBIND11_LONG_FROM_UNSIGNED(src);
1021-
} else {
1022-
if (std::is_signed<T>::value)
1023-
return PyLong_FromLongLong((long long) src);
1024-
else
1025-
return PyLong_FromUnsignedLongLong((unsigned long long) src);
1026-
}
1013+
template<typename U = T>
1014+
static typename std::enable_if<std::is_floating_point<U>::value, handle>::type
1015+
cast(U src, return_value_policy /* policy */, handle /* parent */) {
1016+
return PyFloat_FromDouble((double) src);
1017+
}
1018+
1019+
template<typename U = T>
1020+
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value && (sizeof(U) <= sizeof(long)), handle>::type
1021+
cast(U src, return_value_policy /* policy */, handle /* parent */) {
1022+
return PYBIND11_LONG_FROM_SIGNED((long) src);
1023+
}
1024+
1025+
template<typename U = T>
1026+
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value && (sizeof(U) <= sizeof(unsigned long)), handle>::type
1027+
cast(U src, return_value_policy /* policy */, handle /* parent */) {
1028+
return PYBIND11_LONG_FROM_UNSIGNED((unsigned long) src);
1029+
}
1030+
1031+
template<typename U = T>
1032+
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_signed<U>::value && (sizeof(U) > sizeof(long)), handle>::type
1033+
cast(U src, return_value_policy /* policy */, handle /* parent */) {
1034+
return PyLong_FromLongLong((long long) src);
1035+
}
1036+
1037+
template<typename U = T>
1038+
static typename std::enable_if<!std::is_floating_point<U>::value && std::is_unsigned<U>::value && (sizeof(U) > sizeof(unsigned long)), handle>::type
1039+
cast(U src, return_value_policy /* policy */, handle /* parent */) {
1040+
return PyLong_FromUnsignedLongLong((unsigned long long) src);
10271041
}
10281042

10291043
PYBIND11_TYPE_CASTER(T, _<std::is_integral<T>::value>("int", "float"));

0 commit comments

Comments
 (0)