Skip to content

Commit c10ac6c

Browse files
committed
Make it possible to generate constexpr signatures in C++11 mode
The current C++14 constexpr signatures don't require relaxed constexpr, but only `auto` return type deduction. To get around this in C++11, the type caster's `name()` static member functions are turned into `static constexpr auto` variables.
1 parent f94d759 commit c10ac6c

File tree

9 files changed

+104
-179
lines changed

9 files changed

+104
-179
lines changed

include/pybind11/cast.h

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -778,7 +778,7 @@ template <typename T1, typename T2> struct is_copy_constructible<std::pair<T1, T
778778
template <typename type> class type_caster_base : public type_caster_generic {
779779
using itype = intrinsic_t<type>;
780780
public:
781-
static PYBIND11_DESCR name() { return type_descr(_<type>()); }
781+
static constexpr auto name = type_descr(_<type>());
782782

783783
type_caster_base() : type_caster_base(typeid(type)) { }
784784
explicit type_caster_base(const std::type_info &info) : type_caster_generic(info) { }
@@ -885,7 +885,7 @@ template <typename type> class type_caster<std::reference_wrapper<type>> {
885885
"std::reference_wrapper<T> caster requires T to have a caster with an `T &` operator");
886886
public:
887887
bool load(handle src, bool convert) { return subcaster.load(src, convert); }
888-
static PYBIND11_DESCR name() { return caster_t::name(); }
888+
static constexpr auto name = caster_t::name;
889889
static handle cast(const std::reference_wrapper<type> &src, return_value_policy policy, handle parent) {
890890
// It is definitely wrong to take ownership of this pointer, so mask that rvp
891891
if (policy == return_value_policy::take_ownership || policy == return_value_policy::automatic)
@@ -900,7 +900,7 @@ template <typename type> class type_caster<std::reference_wrapper<type>> {
900900
protected: \
901901
type value; \
902902
public: \
903-
static PYBIND11_DESCR name() { return type_descr(py_name); } \
903+
static constexpr auto name = type_descr(py_name); \
904904
template <typename T_, enable_if_t<std::is_same<type, remove_cv_t<T_>>::value, int> = 0> \
905905
static handle cast(T_ *src, return_value_policy policy, handle parent) { \
906906
if (!src) return none().release(); \
@@ -1049,7 +1049,7 @@ template <> class type_caster<void> : public type_caster<void_type> {
10491049

10501050
template <typename T> using cast_op_type = void*&;
10511051
operator void *&() { return value; }
1052-
static PYBIND11_DESCR name() { return type_descr(_("capsule")); }
1052+
static constexpr auto name = type_descr(_("capsule"));
10531053
private:
10541054
void *value = nullptr;
10551055
};
@@ -1289,7 +1289,7 @@ template <typename CharT> struct type_caster<CharT, enable_if_t<is_std_char_type
12891289
return value[0];
12901290
}
12911291

1292-
static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); }
1292+
static constexpr auto name = type_descr(_(PYBIND11_STRING_NAME));
12931293
template <typename _T> using cast_op_type = remove_reference_t<pybind11::detail::cast_op_type<_T>>;
12941294
};
12951295

@@ -1314,9 +1314,9 @@ template <template<typename...> class Tuple, typename... Ts> class tuple_caster
13141314
return cast_impl(std::forward<T>(src), policy, parent, indices{});
13151315
}
13161316

1317-
static PYBIND11_DESCR name() {
1318-
return type_descr(_("Tuple[") + detail::concat(make_caster<Ts>::name()...) + _("]"));
1319-
}
1317+
static constexpr auto name = type_descr(
1318+
_("Tuple[") + detail::concat(make_caster<Ts>::name...) + _("]")
1319+
);
13201320

13211321
template <typename T> using cast_op_type = type;
13221322

@@ -1461,7 +1461,7 @@ struct move_only_holder_caster {
14611461
auto *ptr = holder_helper<holder_type>::get(src);
14621462
return type_caster_base<type>::cast_holder(ptr, &src);
14631463
}
1464-
static PYBIND11_DESCR name() { return type_caster_base<type>::name(); }
1464+
static constexpr auto name = type_caster_base<type>::name;
14651465
};
14661466

14671467
template <typename type, typename deleter>
@@ -1492,10 +1492,10 @@ template <typename base, typename holder> struct is_holder_type :
14921492
template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
14931493
std::true_type {};
14941494

1495-
template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } };
1496-
template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } };
1497-
template <> struct handle_type_name<args> { static PYBIND11_DESCR name() { return _("*args"); } };
1498-
template <> struct handle_type_name<kwargs> { static PYBIND11_DESCR name() { return _("**kwargs"); } };
1495+
template <typename T> struct handle_type_name { static constexpr auto name = _<T>(); };
1496+
template <> struct handle_type_name<bytes> { static constexpr auto name = _(PYBIND11_BYTES_NAME); };
1497+
template <> struct handle_type_name<args> { static constexpr auto name = _("*args"); };
1498+
template <> struct handle_type_name<kwargs> { static constexpr auto name = _("**kwargs"); };
14991499

15001500
template <typename type>
15011501
struct pyobject_caster {
@@ -1513,7 +1513,7 @@ struct pyobject_caster {
15131513
static handle cast(const handle &src, return_value_policy /* policy */, handle /* parent */) {
15141514
return src.inc_ref();
15151515
}
1516-
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name());
1516+
PYBIND11_TYPE_CASTER(type, handle_type_name<type>::name);
15171517
};
15181518

15191519
template <typename T>
@@ -1826,7 +1826,7 @@ class argument_loader {
18261826
static constexpr bool has_kwargs = kwargs_pos < 0;
18271827
static constexpr bool has_args = args_pos < 0;
18281828

1829-
static PYBIND11_DESCR arg_names() { return detail::concat(make_caster<Args>::name()...); }
1829+
static constexpr auto arg_names = detail::concat(make_caster<Args>::name...);
18301830

18311831
bool load_args(function_call &call) {
18321832
return load_impl_sequence(call, indices{});

include/pybind11/detail/descr.h

Lines changed: 14 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/*
2-
pybind11/detail/descr.h: Helper type for concatenating type signatures
3-
either at runtime (C++11) or compile time (C++14)
2+
pybind11/detail/descr.h: Helper type for concatenating type signatures at compile time
43
54
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
65
@@ -15,13 +14,12 @@
1514
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
1615
NAMESPACE_BEGIN(detail)
1716

18-
/* Concatenate type signatures at compile time using C++14 */
19-
#if defined(PYBIND11_CPP14) && !defined(_MSC_VER)
20-
#define PYBIND11_CONSTEXPR_DESCR
21-
17+
/* Concatenate type signatures at compile time */
2218
template <size_t Size1, size_t Size2> class descr {
2319
template <size_t Size1_, size_t Size2_> friend class descr;
2420
public:
21+
constexpr descr() = default;
22+
2523
constexpr descr(char const (&text) [Size1+1], const std::type_info * const (&types)[Size2+1])
2624
: descr(text, types,
2725
make_index_sequence<Size1>(),
@@ -96,90 +94,21 @@ template <typename Type> constexpr descr<1, 1> _() {
9694
return descr<1, 1>({ '%', '\0' }, { &typeid(Type), nullptr });
9795
}
9896

99-
inline constexpr descr<0, 0> concat() { return _(""); }
100-
template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr) { return descr; }
101-
template <size_t Size1, size_t Size2, typename... Args> auto constexpr concat(descr<Size1, Size2> descr, Args&&... args) { return descr + _(", ") + concat(args...); }
102-
template <size_t Size1, size_t Size2> auto constexpr type_descr(descr<Size1, Size2> descr) { return _("{") + descr + _("}"); }
103-
104-
#define PYBIND11_DESCR constexpr auto
105-
106-
#else /* Simpler C++11 implementation based on run-time memory allocation and copying */
107-
108-
class descr {
109-
public:
110-
PYBIND11_NOINLINE descr(const char *text, const std::type_info * const * types) {
111-
size_t nChars = len(text), nTypes = len(types);
112-
m_text = new char[nChars];
113-
m_types = new const std::type_info *[nTypes];
114-
memcpy(m_text, text, nChars * sizeof(char));
115-
memcpy(m_types, types, nTypes * sizeof(const std::type_info *));
116-
}
117-
118-
PYBIND11_NOINLINE descr operator+(descr &&d2) && {
119-
descr r;
120-
121-
size_t nChars1 = len(m_text), nTypes1 = len(m_types);
122-
size_t nChars2 = len(d2.m_text), nTypes2 = len(d2.m_types);
123-
124-
r.m_text = new char[nChars1 + nChars2 - 1];
125-
r.m_types = new const std::type_info *[nTypes1 + nTypes2 - 1];
126-
memcpy(r.m_text, m_text, (nChars1-1) * sizeof(char));
127-
memcpy(r.m_text + nChars1 - 1, d2.m_text, nChars2 * sizeof(char));
128-
memcpy(r.m_types, m_types, (nTypes1-1) * sizeof(std::type_info *));
129-
memcpy(r.m_types + nTypes1 - 1, d2.m_types, nTypes2 * sizeof(std::type_info *));
130-
131-
delete[] m_text; delete[] m_types;
132-
delete[] d2.m_text; delete[] d2.m_types;
133-
134-
return r;
135-
}
97+
constexpr descr<0, 0> concat() { return _(""); }
13698

137-
char *text() { return m_text; }
138-
const std::type_info * * types() { return m_types; }
99+
template <size_t Size1, size_t Size2>
100+
constexpr descr<Size1, Size2> concat(descr<Size1, Size2> descr) { return descr; }
139101

140-
protected:
141-
PYBIND11_NOINLINE descr() { }
142-
143-
template <typename T> static size_t len(const T *ptr) { // return length including null termination
144-
const T *it = ptr;
145-
while (*it++ != (T) 0)
146-
;
147-
return static_cast<size_t>(it - ptr);
148-
}
149-
150-
const std::type_info **m_types = nullptr;
151-
char *m_text = nullptr;
152-
};
153-
154-
/* The 'PYBIND11_NOINLINE inline' combinations below are intentional to get the desired linkage while producing as little object code as possible */
155-
156-
PYBIND11_NOINLINE inline descr _(const char *text) {
157-
const std::type_info *types[1] = { nullptr };
158-
return descr(text, types);
159-
}
160-
161-
template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(const char *text1, const char *) { return _(text1); }
162-
template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(char const *, const char *text2) { return _(text2); }
163-
template <bool B> PYBIND11_NOINLINE enable_if_t<B, descr> _(descr d, descr) { return d; }
164-
template <bool B> PYBIND11_NOINLINE enable_if_t<!B, descr> _(descr, descr d) { return d; }
165-
166-
template <typename Type> PYBIND11_NOINLINE descr _() {
167-
const std::type_info *types[2] = { &typeid(Type), nullptr };
168-
return descr("%", types);
102+
template <size_t Size1, size_t Size2, typename... Args>
103+
constexpr auto concat(descr<Size1, Size2> d, Args... args)
104+
-> decltype(descr<Size1 + 2, Size2>{} + concat(args...)) {
105+
return d + _(", ") + concat(args...);
169106
}
170107

171-
template <size_t Size> PYBIND11_NOINLINE descr _() {
172-
const std::type_info *types[1] = { nullptr };
173-
return descr(std::to_string(Size).c_str(), types);
108+
template <size_t Size1, size_t Size2>
109+
constexpr descr<Size1 + 2, Size2> type_descr(descr<Size1, Size2> descr) {
110+
return _("{") + descr + _("}");
174111
}
175112

176-
PYBIND11_NOINLINE inline descr concat() { return _(""); }
177-
PYBIND11_NOINLINE inline descr concat(descr &&d) { return d; }
178-
template <typename... Args> PYBIND11_NOINLINE descr concat(descr &&d, Args&&... args) { return std::move(d) + _(", ") + concat(std::forward<Args>(args)...); }
179-
PYBIND11_NOINLINE inline descr type_descr(descr&& d) { return _("{") + std::move(d) + _("}"); }
180-
181-
#define PYBIND11_DESCR ::pybind11::detail::descr
182-
#endif
183-
184113
NAMESPACE_END(detail)
185114
NAMESPACE_END(PYBIND11_NAMESPACE)

include/pybind11/detail/init.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class type_caster<value_and_holder> {
2424

2525
template <typename> using cast_op_type = value_and_holder &;
2626
operator value_and_holder &() { return *value; }
27-
static PYBIND11_DESCR name() { return type_descr(_<value_and_holder>()); }
27+
static constexpr auto name = type_descr(_<value_and_holder>());
2828

2929
private:
3030
value_and_holder *value = nullptr;

include/pybind11/eigen.h

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -180,28 +180,27 @@ template <typename Type_> struct EigenProps {
180180
}
181181
}
182182

183-
static PYBIND11_DESCR descriptor() {
184-
constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
185-
constexpr bool show_order = is_eigen_dense_map<Type>::value;
186-
constexpr bool show_c_contiguous = show_order && requires_row_major;
187-
constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
188-
189-
return type_descr(_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name() +
190-
_("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
191-
_(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
192-
_("]") +
193-
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
194-
// satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
195-
// options, possibly f_contiguous or c_contiguous. We include them in the descriptor output
196-
// to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
197-
// see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
198-
// *gave* a numpy.ndarray of the right type and dimensions.
199-
_<show_writeable>(", flags.writeable", "") +
200-
_<show_c_contiguous>(", flags.c_contiguous", "") +
201-
_<show_f_contiguous>(", flags.f_contiguous", "") +
202-
_("]")
203-
);
204-
}
183+
static constexpr bool show_writeable = is_eigen_dense_map<Type>::value && is_eigen_mutable_map<Type>::value;
184+
static constexpr bool show_order = is_eigen_dense_map<Type>::value;
185+
static constexpr bool show_c_contiguous = show_order && requires_row_major;
186+
static constexpr bool show_f_contiguous = !show_c_contiguous && show_order && requires_col_major;
187+
188+
static constexpr auto descriptor = type_descr(
189+
_("numpy.ndarray[") + npy_format_descriptor<Scalar>::name +
190+
_("[") + _<fixed_rows>(_<(size_t) rows>(), _("m")) +
191+
_(", ") + _<fixed_cols>(_<(size_t) cols>(), _("n")) +
192+
_("]") +
193+
// For a reference type (e.g. Ref<MatrixXd>) we have other constraints that might need to be
194+
// satisfied: writeable=True (for a mutable reference), and, depending on the map's stride
195+
// options, possibly f_contiguous or c_contiguous. We include them in the descriptor output
196+
// to provide some hint as to why a TypeError is occurring (otherwise it can be confusing to
197+
// see that a function accepts a 'numpy.ndarray[float64[3,2]]' and an error message that you
198+
// *gave* a numpy.ndarray of the right type and dimensions.
199+
_<show_writeable>(", flags.writeable", "") +
200+
_<show_c_contiguous>(", flags.c_contiguous", "") +
201+
_<show_f_contiguous>(", flags.f_contiguous", "") +
202+
_("]")
203+
);
205204
};
206205

207206
// Casts an Eigen type to numpy array. If given a base, the numpy array references the src data,
@@ -337,7 +336,7 @@ struct type_caster<Type, enable_if_t<is_eigen_dense_plain<Type>::value>> {
337336
return cast_impl(src, policy, parent);
338337
}
339338

340-
static PYBIND11_DESCR name() { return props::descriptor(); }
339+
static constexpr auto name = props::descriptor;
341340

342341
operator Type*() { return &value; }
343342
operator Type&() { return value; }
@@ -385,7 +384,7 @@ template <typename MapType> struct eigen_map_caster {
385384
}
386385
}
387386

388-
static PYBIND11_DESCR name() { return props::descriptor(); }
387+
static constexpr auto name = props::descriptor;
389388

390389
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
391390
// types but not bound arguments). We still provide them (with an explicitly delete) so that
@@ -530,7 +529,7 @@ struct type_caster<Type, enable_if_t<is_eigen_other<Type>::value>> {
530529
}
531530
static handle cast(const Type *src, return_value_policy policy, handle parent) { return cast(*src, policy, parent); }
532531

533-
static PYBIND11_DESCR name() { return props::descriptor(); }
532+
static constexpr auto name = props::descriptor;
534533

535534
// Explicitly delete these: support python -> C++ conversion on these (i.e. these can be return
536535
// types but not bound arguments). We still provide them (with an explicitly delete) so that
@@ -597,7 +596,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
597596
}
598597

599598
PYBIND11_TYPE_CASTER(Type, _<(Type::IsRowMajor) != 0>("scipy.sparse.csr_matrix[", "scipy.sparse.csc_matrix[")
600-
+ npy_format_descriptor<Scalar>::name() + _("]"));
599+
+ npy_format_descriptor<Scalar>::name + _("]"));
601600
};
602601

603602
NAMESPACE_END(detail)

include/pybind11/functional.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,8 @@ struct type_caster<std::function<Return(Args...)>> {
7575
return cpp_function(std::forward<Func>(f_), policy).release();
7676
}
7777

78-
PYBIND11_TYPE_CASTER(type, _("Callable[[") +
79-
argument_loader<Args...>::arg_names() + _("], ") +
80-
make_caster<retval_type>::name() +
81-
_("]"));
78+
PYBIND11_TYPE_CASTER(type, _("Callable[[") + argument_loader<Args...>::arg_names + _("], ")
79+
+ make_caster<retval_type>::name + _("]"));
8280
};
8381

8482
NAMESPACE_END(detail)

0 commit comments

Comments
 (0)