906. ObjectType is the wrong concept to constrain initializer_list

Section: 21.9 [support.initlist] Status: NAD Concepts Submitter: Daniel Krügler Opened: 2008-09-26 Last modified: 2016-02-10

Priority: Not Prioritized

View other active issues in [support.initlist].

View all other issues in [support.initlist].

View all issues with NAD Concepts status.

Discussion:

The currently proposed constraint on initializer_list's element type E is that is has to meet ObjectType. This is an underspecification, because both core language and library part of initializer_list make clear, that it references an implicitly allocated array:

11.6.4 [dcl.init.list]/4:

When an initializer list is implicitly converted to a std::initializer_list<E>, the object passed is constructed as if the implementation allocated an array of N elements of type E, where N is the number of elements in the initializer list.[..]

21.9 [support.initlist]/2.

An object of type initializer_list<E> provides access to an array of objects of type const E.[..]

Therefore, E needs to fulfill concept ValueType (thus excluding abstract class types). This stricter requirement should be added to prevent deep instantiation errors known from the bad old times, as shown in the following example:

// Header A: (Should concept-check even in stand-alone modus)

template <DefaultConstructible T>
requires MoveConstructible<T>
void generate_and_do_3(T a) {
  std::initializer_list<T> list{T(), std::move(a), T()};
  ...
}

void do_more();
void do_more_or_less();

template <DefaultConstructible T>
requires MoveConstructible<T>
void more_generate_3() {
  do_more();
  generate_and_do_3(T());
}

template <DefaultConstructible T>
requires MoveConstructible<T>
void something_and_generate_3() {
  do_more_or_less();
  more_generate_3();
}

// Test.cpp

#include "A.h"

class Abstract {
public:
  virtual ~Abstract();
  virtual void foo() = 0; // abstract type
  Abstract(Abstract&&){} // MoveConstructible
  Abstract(){} // DefaultConstructible
};

int main() {
  // The restricted template *accepts* the argument, but
  // causes a deep instantiation error in the internal function
  // generate_and_do_3:
  something_and_generate_3<Abstract>();
}

The proposed stricter constraint does not minimize the aim to support more general containers for which ObjectType would be sufficient. If such an extended container (lets assume it's still a class template) provides a constructor that accepts an initializer_list only this constructor would need to be restricted on ValueType:

template<ObjectType T>
class ExtContainer {
public:
  requires ValueType<T>
  ExtContainer(std::initializer_list<T>);
  ...
};

[ Batavia (2009-05): ]

Move to Tentatively Ready.

[ 2009-07 Frankfurt: ]

Need to look at again without concepts.

Proposed resolution:

  1. In 21.9 [support.initlist]/p.1 replace in "header <initializer_list> synopsis" the constraint "ObjectType" in the template parameter list by the constraint "ValueType".