1. Revision History
R1
-
Renamed the proposed facility from
tostd :: rebind .std :: rebind_cast -
Expanded § 5.5 Naming with a comparison against the established
family and an explicit rejection of the bare_cast name.rebind -
The type trait remains named
(preserving the precedent fromrebind_t ); only the value-producing operation gains thestd : simd suffix._cast -
Updated all examples and wording to reflect the new name.
R0
-
Initial revision
2. Motivation
Modern C++ provides powerful facilities for generic programming, but lacks a uniform way to change the element type of containers and container-like types. Consider a simple requirement: convert a container of into the corresponding container of , without the caller having to know what kind of container it is.
For , this is straightforward using constructor-based conversion:
std :: vector < double > widen ( const std :: vector < float >& data ) { return std :: vector < double > ( data . begin (), data . end ()); }
However, making this work for requires completely different code:
template < std :: size_t N > std :: array < double , N > widen ( const std :: array < float , N >& data ) { std :: array < double , N > result ; std :: copy ( data . begin (), data . end (), result . begin ()); return result ; }
For , yet another approach is needed:
std :: complex < double > widen ( const std :: complex < float >& data ) { return std :: complex < double > ( data ); }
Each type requires specialised knowledge of its conversion mechanisms. Attempting to write a single generic function fails:
template < typename Container > auto widen_to_double ( const Container & data ) { using T = typename Container :: value_type ; // Some container types may not even have this member. // How do we create Container<double> from Container<float>? // - vector: range constructor // - array: manual copy with known size // - complex: direct construction // - user types: ??? // No uniform solution exists }
2.1. Precedent in std::simd
recognised this problem and introduced as a type trait to convert the type to . This works well for , but the same need exists across containers, , and user-defined uniform-element types.
Recent discussion of simd casting utilities [P3445R0] raised questions about whether such facilities should be generalised beyond simd to support other types like containers and units. This proposal explores that generalisation.
2.2. Proposed Solution
We propose two complementary facilities:
-
: a type trait that computes the result type of rebinding the structure ofrebind_t < U , T > to use elements of typeT .U -
: a customisation point object that performs the element-wise conversion and produces a new object of typerebind_cast < U > ( obj ) .rebind_t < U , decltype ( obj ) >
The type trait keeps the established name, mirroring and / . The value-producing operation takes the suffix to make explicit that it is a named, type-directed, value-producing conversion, like , , and .
These facilities work together to enable uniform generic code:
template < typename Container > auto widen_to_double ( const Container & data ) { return std :: rebind_cast < double > ( data ); } // Works uniformly for all supported types: std :: vector < float > v = { 1.0f , 2.0f , 3.0f }; auto vd = widen_to_double ( v ); // vector<double> std :: array < float , 3 > a = { 1.0f , 2.0f , 3.0f }; auto ad = widen_to_double ( a ); // array<double, 3>
The facilities are extensible via ADL, allowing user-defined types to participate in generic algorithms using the same interface.
3. Supported Types
3.1. Specification Principle
is provided for types where rebinding the element type produces a meaningful corresponding type. The presence of a member typedef is a strong indicator that a type has a uniform element type, but it is neither necessary nor sufficient on its own:
-
Types like
are clearly rebindable despite lackingcomplex < T > .value_type -
Types like
havestd :: stack < T > but cannot be rebound without additional complexity (rebinding the underlying container).value_type -
Associative containers have
but require also rebinding their comparator.value_type
The determination of whether a type is rebindable depends on whether the rebinding operation is well-defined and produces a semantically equivalent structure with a different element type.
Standard library support is provided for:
-
Sequence containers: types with
representing a sequence of uniform elements.value_type -
Scalar types with uniform components: types like
that represent a single value composed of uniform components.complex < T > -
User-defined types: via ADL customisation for types where rebinding is appropriate.
3.2. Standard Library Support
The following table shows the standard library types for which and would be defined:
| Input type | Has ?
| Result of rebinding to
|
|---|---|---|
| Yes |
|
| Yes |
|
| Yes |
|
| Yes |
|
| Yes |
|
| No (special case) |
|
For allocator-aware containers, the allocator is automatically rebound using , following existing standard library practice.
For types see § 5.8 Relationship with std::simd::rebind_t for the relationship with the existing trait.
3.3. User-Defined Types
User-defined types can provide support via ADL by defining a function in the same namespace as the type:
namespace mylib { template < typename T > struct Vec3 { using value_type = T ; // Strong hint that rebinding makes sense. T x , y , z ; }; template < typename U , typename T > Vec3 < U > rebind_cast ( const Vec3 < T >& v ) { return Vec3 < U > { static_cast < U > ( v . x ), static_cast < U > ( v . y ), static_cast < U > ( v . z )}; } } // rebind_t works automatically: static_assert ( std :: is_same_v < std :: rebind_t < double , mylib :: Vec3 < float >> , mylib :: Vec3 < double >> );
3.4. Excluded Types
Associative containers (, , etc.) are not supported because rebinding the element type requires also rebinding the comparator type, which lacks a general solution. See § 5.4 Associative Containers.
Tuple-like types (, ) are excluded because they are fundamentally heterogeneous types. See § 5.2 Tuple and Pair.
Container adaptors (, , ) are not included in initial support. See § 5.3 Container Adaptors.
Duration and units types (e.g., ) are not included in the initial standard library support due to ambiguity about what should be rebound (see § 5.10 Duration and Units Types), but such types may opt in via the ADL customisation mechanism if their authors define appropriate semantics.
4. Examples
4.1. Basic Usage
Converting element types is straightforward with :
// Arrays - preserves size std :: array < float , 4 > af = { 1.0f , 2.0f , 3.0f , 4.0f }; std :: array < double , 4 > ad = std :: rebind_cast < double > ( af ); // Type computation using ArrayDouble4 = std :: rebind_t < double , decltype ( af ) > ; static_assert ( std :: is_same_v < ArrayDouble4 , std :: array < double , 4 >> ); // Vectors - preserves (rebound) allocator std :: vector < int > vi = { 1 , 2 , 3 , 4 , 5 }; std :: vector < long > vl = std :: rebind_cast < long > ( vi ); // Complex numbers std :: complex < float > cf { 3.0f , 4.0f }; std :: complex < double > cd = std :: rebind_cast < double > ( cf );
4.2. Generic Type Conversion
Structure-preserving type conversion works uniformly across container types:
template < typename U , typename Container > auto convert_elements ( const Container & c ) { return std :: rebind_cast < U > ( c ); } std :: array < int , 5 > ints = { 1 , 2 , 3 , 4 , 5 }; auto doubles = convert_elements < double > ( ints ); // array<double, 5> std :: vector < float > floats = { 1.0f , 2.0f }; auto longs = convert_elements < long > ( floats ); // vector<long>
4.3. Complex Numbers
works uniformly for :
// Complex number precision conversion std :: complex < float > cf { 3.0f , 4.0f }; auto cd = std :: rebind_cast < double > ( cf ); // complex<double>{3.0, 4.0} // Useful for mixed-precision algorithms template < typename T > auto high_precision_norm ( const std :: complex < T >& c ) { auto hp = std :: rebind_cast < long double > ( c ); return std :: abs ( hp ); // Computed in higher precision }
4.4. User-Defined Types
Users can extend to their own types via ADL:
namespace mylib { template < typename T > struct Vec3 { using value_type = T ; // Strong hint that rebinding is allowed. T x , y , z ; }; // Provide rebind_cast via ADL template < typename U , typename T > Vec3 < U > rebind_cast ( const Vec3 < T >& v ) { return Vec3 < U > { static_cast < U > ( v . x ), static_cast < U > ( v . y ), static_cast < U > ( v . z ) }; } } // Now Vec3 works with generic code: mylib :: Vec3 < float > vf { 1.0f , 2.0f , 3.0f }; auto vd = convert_elements < double > ( vf ); // Vec3<double> // And rebind_t works automatically: using Vec3d = std :: rebind_t < double , mylib :: Vec3 < float >> ; static_assert ( std :: is_same_v < Vec3d , mylib :: Vec3 < double >> );
5. Design Alternatives
5.1. Range Adaptor Syntax
could support range adaptor syntax to enable composition with other range adaptors:
auto result = input | std :: rebind_cast < double > | std :: views :: take ( 10 );
This would follow the pattern of modern C++ range adaptors and enable natural pipelines. However, this functionality is deferred to future work to keep the initial proposal focused on core functionality.
5.2. Tuple and Pair
and are excluded because they are fundamentally heterogeneous types, even when all their element types happen to be the same.
Consider:
std :: tuple < int , int , int > t = { 1 , 2 , 3 }; std :: pair < int , int > p = { 1 , 2 }; auto t2 = std :: rebind_cast < double > ( t ); // What does this mean? auto p2 = std :: rebind_cast < double > ( p ); // Which elements to rebind?
The problem is not whether the types are currently the same, but that tuples (including , which is a 2-element tuple) are designed to hold potentially different types at each position. Without additional semantic constraints, the meaning of "rebind" is ambiguous for tuple-like types.
Users who need to convert tuple or pair elements can explicitly construct the target type:
std :: pair < int , int > p = { 1 , 2 }; std :: pair < double , double > pd { static_cast < double > ( p . first ), static_cast < double > ( p . second )};
5.3. Container Adaptors
Container adaptors (, , ) wrap underlying containers and present implementation challenges: the underlying container type is a template parameter that must itself be rebound, and the rebinding operation may need to traverse the adaptor’s interface to extract elements.
This proposal excludes container adaptors from initial support. They can be added in future revisions once implementation experience is gained. Users who need to rebind adapted containers can rebind the underlying container type explicitly.
5.4. Associative Containers
, , and related associative containers are excluded from this proposal because rebinding their element type requires also rebinding their comparator type, which lacks a general solution.
Consider:
std :: set < float , MyFloatCompare > s = /*...*/ ; auto s2 = std :: rebind_cast < double > ( s ); // What comparator should s2 use?
The result type would need to be . Options include:
-
Use
— loses the custom comparator, changes semantics.std :: less -
Attempt to rebind the comparator — no general mechanism exists for this; comparators may not be templated.
-
Require users to provide the comparator — defeats the purpose of
being simple.rebind_cast
None of these solutions is satisfactory. The comparator-rebinding problem is orthogonal to element-type rebinding and requires separate consideration. For now, associative containers are excluded.
A future proposal could address this by:
-
Defining a
mechanism for comparators.rebind_comparator -
Extending
to accept optional comparator arguments.rebind_cast -
Restricting support to comparators known to be rebindable (e.g.,
).std :: less
Such extensions are beyond the scope of this proposal.
5.5. Naming
5.5.1. Consistency with the established _cast family
C++ has a well-established family of named, type-directed, value-producing conversions whose names end in . The shared characteristic is that each takes an explicit target type and produces a value of a related type from its argument. In the core language:
-
,static_cast ,dynamic_cast ,const_cast .reinterpret_cast
This family has continued to grow and is the convention for new function-style type-directed conversions:
-
(C++20) — type-directed reinterpretation between trivially-copyable types.std :: bit_cast -
(C++26, [P0543R3]) — type-directed numeric conversion with saturation semantics.std :: saturating_cast -
The smart-pointer cast family:
,std :: static_pointer_cast ,std :: dynamic_pointer_cast ,std :: const_pointer_cast .std :: reinterpret_pointer_cast -
The chrono cast family:
,std :: chrono :: duration_cast .std :: chrono :: time_point_cast
matches the family’s invocation pattern precisely:
auto y = std :: bit_cast < U > ( x ); // C++20: reinterpret bits as U auto y = std :: saturating_cast < U > ( x ); // C++26: numeric conversion of x with saturation auto y = std :: rebind_cast < U > ( x ); // rebind x’s structure to use elements of type U
A new function-style, type-directed conversion in C++29 should join this family. Adopting is the consistent choice.
5.5.2. Comparison with other candidate names
| Candidate | Verdict | Rationale |
|---|---|---|
| Rejected | Departs from the convention for new function-style type-directed conversions, and conflates the type alias and the operation under a single name.
|
| Proposed | Joins the established family; pairs naturally with under the / convention; preserves the root, inheriting vocabulary from and SIMD .
|
| Rejected | Awkward for non-container types like (no obvious "element"); loses the root vocabulary.
|
| Rejected | Suggests conversion of a single value; misses the structural aspect (allocator rebinding, container reconstruction); loses the root vocabulary.
|
| Considered | Accurate but heavy; coins a new term; less consistent with the compact names in the family.
|
| Rejected | Vague; loses the vocabulary; not in the family.
|
| Rejected | Too generic; doesn’t convey the type-directed aspect; not in the family.
|
5.5.3. Disambiguation from std :: simd :: rebind
As a minor secondary benefit, the suffix also avoids any potential confusion with (introduced in C++26). That trait lives in a different namespace and is a different kind of entity (a type-level alias template, not a value-producing operation), so there is no technical clash to resolve and no ambiguity at the language level. But because the existence of the SIMD-namespace trait was the original prompt for considering the suffix, it is worth recording that this is a side benefit, not the driving motivation.
The choice of would be equally appropriate even if no -named entity existed elsewhere in the standard library: the and consistency arguments above stand on their own.
The earlier C++03 nested member of was deprecated in C++17 and removed in C++20 and is not relevant here.
5.6. Customisation Mechanism
The proposal uses a customisation point object with ADL lookup, following the precedent of and other customisable standard library operations. We also provide the type trait for use in compile-time contexts. The ADL hook is named (matching the user-facing CPO), so user types provide:
namespace user_ns { template < typename U , typename T > auto rebind_cast ( const UserType < T >& ) -> UserType < U > ; }
5.7. Relationship Between rebind_t and rebind_cast
The type trait is defined in terms of the function :
template < typename U , typename T > using rebind_t = decltype ( rebind_cast < U > ( declval < T > ()));
This ensures consistency: the type trait always produces the same type that the operation returns. An alternative would be to define them independently, but that creates potential for inconsistency and increases the customisation burden on user types (they would have to specialise both). Defining the trait in terms of the operation means users only need to provide one ADL hook.
5.8. Relationship with std :: simd :: rebind_t
C++26 introduces , a SIMD-specific type-level alias that maps a SIMD type to the corresponding SIMD type with a different element type. Once is added by this proposal, every specialisation will be reachable by two spellings of essentially the same idea:
// Route A: SIMD-native trait (existing in C++26). using A = std :: simd :: rebind_t < float , std :: simd :: basic_vec < int , Abi >> ; // Route B: generalised trait proposed by this paper. using B = std :: rebind_t < float , std :: simd :: basic_vec < int , Abi >> ;
This is not a problem since the two names live in different namespaces, and would produce the same result type for SIMD inputs. However, it does need to be explicitly specified, so this subsection records the relationship and the equivalence guarantee.
5.8.1. Coexistence
Both spellings continue to exist. We do not propose to remove or deprecate / :
-
They are part of C++26 and are about to ship; deprecating them in C++29 with no usage-experience cycle would be premature.
-
Source-compatibility for early adopters of
matters.std :: simd -
The two spellings serve subtly different purposes:
is the right tool when code is specifically written againststd :: simd :: rebind_t ;std :: simd is the right tool for generic code that works uniformly across containers,std :: rebind_t , SIMD, and user-defined types.complex
5.8.2. Equivalence guarantee
For any specialisation of , this proposal requires:
denotes the same type asstd :: rebind_t < U , std :: simd :: basic_vec < T , Abi >> .std :: simd :: rebind_t < U , std :: simd :: basic_vec < T , Abi >>
This is a portability guarantee that users can rely on in concept constraints, partial specialisations, and overload resolution. It is not a coincidence to be observed by inspection.
The cleanest way to enforce the guarantee in the standard library wording is to specify the SIMD overload of so that its return type is :
// Standard library overload for std::simd::basic_vec: template < class U , class T , class Abi > constexpr std :: simd :: rebind_t < U , std :: simd :: basic_vec < T , Abi >> rebind_cast ( const std :: simd :: basic_vec < T , Abi >& x );
Since is itself defined as (see § 5.7 Relationship Between rebind_t and rebind_cast), this specification chain makes the equivalence hold by construction: is, by definition, whatever the SIMD overload of returns, which is by definition .
5.8.3. Customisation goes through rebind_cast , not via trait specialisation
Because is an alias defined in terms of , users (including future SIMD ABIs) should not attempt to extend rebinding behaviour by specialising or directly. The supported customisation path is to provide an ADL overload for the type concerned. The trait will then automatically reflect the operation’s behaviour.
This avoids the risk of drift between the trait and the operation, and keeps a single point of customisation.
5.8.4. Guidance for users
-
In generic code that may operate on containers,
, SIMD types, or user-defined types: preferstd :: complex andstd :: rebind_t .std :: rebind_cast -
In SIMD-specific code that is statically constrained to
: either spelling is correct;std :: simd :: basic_vec may be the more idiomatic choice for code that is otherwise written againststd :: simd :: rebind_t names.std :: simd ::* -
In all cases the two spellings are guaranteed to denote the same type for SIMD inputs.
5.9. Value-Preserving Conversions
This proposal does not impose special requirements for value-preserving conversions beyond standard C++ conversion rules. The element-wise conversion from to uses standard conversion semantics (equivalent to for each element).
std :: vector < double > vd = { 3.14 , 2.71 }; auto vi = rebind_cast < int > ( vd ); // OK - explicitly requested narrowing
This follows the precedent of , which uses constructor explicitness to control conversion safety:
-
Non-explicit constructors allow implicit conversions (i.e., conversion must be widening/value-preserving).
-
Explicit constructors permit narrowing conversions.
For , the explicit, named cast call site is the user’s signal that the conversion is intended, including narrowing conversions. This matches the precedent of , , and : the named cast itself is the opt-in.
An alternative would be to require value-preserving conversions by default and provide a parameter (following ’s pattern for range load/store operations) to opt into narrowing:
std :: rebind_cast < int > ( vd ); // Error - narrowing std :: rebind_cast < int > ( vd , std :: flag_convert ); // OK - explicit opt-in
However, this adds complexity without clear benefit:
-
is always an explicit, named cast, so the user has already opted in.rebind_cast -
For generic code, the caller controls what conversions are valid.
-
Standard C++ conversion rules already provide appropriate diagnostics (e.g., for explicit constructors).
-
User-defined types can use
constructors to control conversion safety.explicit
The current design is simpler and follows the principle that explicit cast calls indicate explicit intent — exactly as for and .
5.10. Duration and Units Types
Types representing quantities with units, such as or quantity types from units proposals like [P3045R1], are not included in the initial standard library support for this proposal.
Such types present ambiguity about what should be rebound:
-
For
, rebinding could mean changing the representation type (std :: chrono :: duration < Rep , Period > ) or the units (Rep ).Period -
The semantics of rebinding are unclear without additional context.
Additionally, already provides conversion functionality for duration types, and is itself already a member of the family that this proposal joins.
However, the ADL customisation mechanism allows such types to provide their own support if appropriate semantics can be established. Future proposals (including units proposals) can define for duration/units types if a suitable interpretation is agreed upon.
6. Implementation Experience
has been prototyped for (case 5 of § 7.2.3 Customisation point object rebind_cast) within an experimental codebase.
The remaining standard-library cases (, , , , , ) and the ADL hook for user-defined types are mechanical extensions; a reference implementation covering some of these is available at: https://godbolt.org/z/aqK469x9e.
7. Wording
The wording below is provided to support LEWG’s design review.
7.1. Header < utility > synopsis additions
The following declarations are added to the synopsis of :
namespace std { // [utility.rebind], generalised element-type rebinding // Type alias trait. template < class U , class T > using rebind_t = decltype ( rebind_cast < U > ( declval < T > ())); // Customisation point object. // (Implementations may realise this as a function template, a function // object, or any other mechanism; see [[#wording_rebind_cast_cpo]] Note 2.) template < class U , class T > constexpr /* see below */ rebind_cast ( T && t ); }
7.2. [utility.rebind] Generalised element-type conversion
This subclause specifies the type alias and the customisation point object , which together provide a uniform interface for converting the element type of containers, scalar uniform-element types, SIMD vectors, and user-defined uniform-element types.
7.2.1. General
produces a new value whose structure mirrors that of , with each constituent element converted from its source type to using ordinary C++ conversion semantics. is the type of that value when has type .
The two facilities are linked by definition: the trait is specified in terms of the operation, ensuring that any type for which is well-formed is automatically supported by , and that the trait and the operation cannot disagree.
7.2.2. Type alias rebind_t
template < class U , class T > using rebind_t = decltype ( std :: rebind_cast < U > ( declval < T > ()));
Mandates: is a well-formed expression.
[Note 1: is therefore SFINAE-friendly: in a substitution context, it is well-formed if and only if is well-formed for an argument of type . This makes usable in concept constraints, e.g. . — end note]
[Note 2: For any specialisation of , denotes the same type as . — end note]
7.2.3. Customisation point object rebind_cast
The name denotes a customisation point object ([customization.point.object]). For a type and a subexpression whose type, after removal of cv-ref qualification, is , the expression is expression-equivalent to:
-
an object of type
whose i-th element equalsstd :: array < U , N > , ifstatic_cast < U > ( E [ i ]) isT for some typestd :: array < V , N > and constantV , and eachN is well-formed; otherwisestatic_cast < U > ( E [ i ]) -
an object of type
whose elements are, in order,std :: vector < U , allocator_traits < A >:: template rebind_alloc < U >> for each elementstatic_cast < U > ( e ) ofe , ifE isT for somestd :: vector < V , A > andV , and the corresponding rebound allocator and element conversions are well-formed; otherwiseA -
analogously for
,std :: deque < V , A > , andstd :: list < V , A > : the result type is the corresponding container template with first argumentstd :: forward_list < V , A > and second argumentU , and the elements areallocator_traits < A >:: template rebind_alloc < U > for each elementstatic_cast < U > ( e ) ofe , in order; otherwiseE -
, ifstd :: complex < U > ( static_cast < U > ( E . real ()), static_cast < U > ( E . imag ())) isT for somestd :: complex < V > and the conversions are well-formed; otherwiseV -
an object of type
whose i-th lane equalsstd :: simd :: rebind_t < U , T > , ifstatic_cast < U > ( E [ i ]) is a specialisation ofT ; otherwisestd :: basic_simd -
, where the meaning of the unqualified namerebind_cast < U > ( E ) is established as if by performing argument-dependent lookup ([basic.lookup.argdep]) only, treatingrebind_cast as a function template that takes one explicit type-template argument followed by a function-call-argument list, if that lookup finds at least one declaration and the resulting call is well-formed; otherwiserebind_cast -
is ill-formed.std :: rebind_cast < U > ( E )
Effects: The result is a new object whose elements (or component values) are the conversions, by , of the corresponding elements of .
Exception safety: If any element conversion exits via an exception, the call to exits via that exception. is unaffected. No allocation performed during the construction of the result (for cases 2 and 3) leaks: any partially-constructed result is destroyed in the usual manner before the exception propagates.
[Note 1: The trait (see § 7.2.2 Type alias rebind_t) is well-formed exactly when applied to a value of type is well-formed, by definition. — end note]
[Note 2: This specification deliberately does not name any implementation-detail namespace. Implementations are free to realise the dispatch using any mechanism — for example a function object, hidden in-namespace overloads, or — provided the observable expression-equivalences above are preserved. Standard-library types added in future revisions are supported by amending the list of cases above. User-defined types hook in via the ADL fallback (case 6). — end note]
[Note 3: Element conversion uses . If is constructible from the element type via an explicit constructor, that constructor participates; if narrowing occurs, it is the user’s choice (the named cast is itself the explicit opt-in). See § 5.9 Value-Preserving Conversions for design discussion. — end note]
7.2.4. Relationship with std :: simd :: rebind_t
For any specialisation :
-
andstd :: rebind_t < U , T > denote the same type.std :: simd :: rebind_t < U , T > -
The result of
for anstd :: rebind_cast < U > ( E ) of typeE has typeT , by the wording of § 7.2.3 Customisation point object rebind_cast case 5.std :: simd :: rebind_t < U , T >
This guarantee is normative: programs may rely on it in concept constraints, partial specialisations, and overload resolution.
[Note: See § 5.8 Relationship with std::simd::rebind_t for the design rationale and guidance on which spelling to use in which context. — end note]
7.2.5. Customisation by user-defined types
A user-defined type may opt into support by providing, in an associated namespace ([basic.lookup.argdep]) of the type, a function template named taking one explicit type-template argument followed by a function-call-argument list. Such a function is found via case 6 of § 7.2.3 Customisation point object rebind_cast.
The provided function shall return a value whose type is the corresponding rebound type for the user’s type, and whose constituent elements (or components) are obtained by element-wise conversion from those of the source value, in a manner consistent with the meaning of the user’s type.
[Example:
namespace mylib { template < class T > struct Vec3 { using value_type = T ; T x , y , z ; }; template < class U , class T > Vec3 < U > rebind_cast ( const Vec3 < T >& v ) { return Vec3 < U > { static_cast < U > ( v . x ), static_cast < U > ( v . y ), static_cast < U > ( v . z ) }; } } mylib :: Vec3 < float > vf { 1.f , 2.f , 3.f }; auto vd = std :: rebind_cast < double > ( vf ); // OK, mylib::Vec3<double> static_assert ( std :: is_same_v < std :: rebind_t < double , mylib :: Vec3 < float >> , mylib :: Vec3 < double >> );
— end example]
A user-defined type shall not provide an overload of that, when found via case 6, returns a value of a standard-library type for which a higher-priority case in § 7.2.3 Customisation point object rebind_cast is also applicable; the behaviour of programs that violate this is unspecified. [Note: This rule prevents users from accidentally redefining the meaning of for standard-library types. — end note]
7.3. Feature-test macro
Add to [version.syn]:
#define __cpp_lib_rebind_cast YYYYMML // also in <utility>
The value is to be assigned by the editor at the time of adoption.