dynarray
constructor ambiguitySection: 99 [arrays.ts::dynarray.cons] Status: NAD Arrays Submitter: Jonathan Wakely Opened: 2013-04-23 Last modified: 2016-03-08
Priority: 0
View all issues with NAD Arrays status.
Discussion:
Addresses: arrays.ts
These constructors can interact badly::
template<class Alloc> dynarray(size_type c, const Alloc& alloc); dynarray(size_type c, const T& v);
Unless the second argument is a value of exactly the type T
you will get the first constructor, i.e.
all of these will fail to compile:
dynarray<long> dlong(1, 1); // 1 is not long dynarray<float> dflt(1, 1.0); // 1.0 is not float dynarray<int*> dptr(1, nullptr); // nullptr is not int* dynarray<void*> doh(1, 0); // 0 is not void*
The nullptr
case is particularly annoying, a user trying to do the right thing by saying nullptr
instead of NULL
still gets the wrong result.
Alloc
shall meet the requirements for an Allocator"
but doesn't actually say "shall not participate in overload resolution unless ..."
I believe we have no precedent for using SFINAE to check "the requirements for an Allocator" because it's
a pretty complicated set of requirements. We could say it shall not participate in overload resolution if Alloc
is implicitly convertible to value_type
.
Alternatively, we could follow the same approach used by other types that can be constructed with an unconstrained
allocator type and use std::allocator_arg_t
as the first argument instead of adding an allocator after the
other arguments.
[2013-09 Chicago:]
Move to Deferred. This feature will ship after C++14 and should be revisited then.
[2014-06-06 pre-Rapperswil]
This issue has been reopened as arrays-ts.
[2014-06-16 Rapperswil]
Move to Ready for alternative A
Previous resolution [SUPERSEDED]:
Either use the correct way to unambiguously call a constructor taking any type of allocator, i.e. change the constructors to take
dynarray(std::allocator_arg_t, const Alloc&, ...)
by modifying both the synopsis 99 [arrays.ts::dynarray.overview] p2 and 99 [arrays.ts::dynarray.cons] before p9 like so:template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const T& v, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, const dynarray& d, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, initializer_list<T>, const Alloc& alloc);or constrain the problematic constructor by adding a new paragraph to 99 [arrays.ts::dynarray.cons]:
template <class Alloc> dynarray(size_type c, const Alloc& alloc); template <class Alloc> dynarray(size_type c, const T& v, const Alloc& alloc); template <class Alloc> dynarray(const dynarray& d, const Alloc& alloc); template <class Alloc> dynarray(initializer_list<T>, const Alloc& alloc);-9- Requires:
-10- Effects: Equivalent to the preceding constructors except that each element is constructed with uses-allocator construction (20.2.8.2 [allocator.uses.construction]). -?- Remarks: The first constructor shall not participate in overload resolution unlessAlloc
shall meet the requirements for an Allocator (16.4.4.6 [allocator.requirements]).Alloc
is not implicitly convertible toT
.
[2014/11 Urbana]
Held at Ready status, pending clarification of Arrays TS
Proposed resolution:
Use the correct way to unambiguously call a constructor taking any type of allocator, i.e. change the
constructors to take dynarray(std::allocator_arg_t, const Alloc&, ...)
by modifying both the synopsis
99 [arrays.ts::dynarray.overview] p2 and 99 [arrays.ts::dynarray.cons] before p9 like so:
template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, size_type c, const T& v, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, const dynarray& d, const Alloc& alloc); template <class Alloc> dynarray(allocator_arg_t, const Alloc& a, initializer_list<T>, const Alloc& alloc);