2255. [arrays.ts] dynarray constructor ambiguity

Section: 99 [arrays.ts::dynarray.cons] Status: NAD Arrays Submitter: Jonathan Wakely Opened: 2013-04-23 Last modified: 2016-03-09

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.

The constructor taking an allocator requires that "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]:

  1. 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);
    
  2. 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: Alloc shall meet the requirements for an Allocator (20.5.3.5 [allocator.requirements]).

    -10- Effects: Equivalent to the preceding constructors except that each element is constructed with uses-allocator construction (23.10.8.2 [allocator.uses.construction]).

    -?- Remarks: The first constructor shall not participate in overload resolution unless Alloc is not implicitly convertible to T.

[2014/11 Urbana]

Held at Ready status, pending clarification of Arrays TS

Proposed resolution:

  1. 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);