Title
[arrays.ts] dynarray constructor ambiguity
Status
open
Section
[dynarray.cons]
Submitter
Jonathan Wakely

Created on 2013-04-23.00:00:00 last changed 98 months ago

Messages

Date: 2014-11-08.18:01:47

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 [dynarray.overview] p2 and [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);
    
Date: 2014-11-08.18:01:47

[ 2014/11 Urbana ]

Held at Ready status, pending clarification of Arrays TS

Date: 2014-06-16.00:00:00

[ 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 [dynarray.overview] p2 and [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 [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 ([allocator.requirements]).

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

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

Date: 2014-06-06.00:00:00

[ 2014-06-06 pre-Rapperswil ]

This issue has been reopened as arrays-ts.

Date: 2014-06-06.21:18:30

[ 2013-09 Chicago: ]

Move to Deferred. This feature will ship after C++14 and should be revisited then.

Date: 2014-06-07.16:56:56

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.

History
Date User Action Args
2016-03-08 23:03:34adminsetstatus: ready -> open
2014-11-08 18:01:47adminsetmessages: + msg7188
2014-11-08 18:01:47adminsetstatus: voting -> ready
2014-11-04 10:26:50adminsetstatus: ready -> voting
2014-06-16 23:29:05adminsetmessages: + msg7047
2014-06-16 23:29:05adminsetstatus: open -> ready
2014-06-06 21:18:30adminsetmessages: + msg6991
2014-06-06 21:18:30adminsetstatus: deferred -> open
2013-09-26 11:12:18adminsetmessages: + msg6627
2013-09-26 11:12:18adminsetstatus: new -> deferred
2013-05-20 18:10:17adminsetmessages: + msg6522
2013-04-23 00:00:00admincreate