Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

CWG2856 [class.conv.ctor] Copy list initialization with explicit and converting constructors #486

Copy link
Copy link
Closed
cplusplus/draft
#6906
cplusplus/draft#6906
@ranaanoop

Description

@ranaanoop
Issue body actions

Full name of submitter: Anoop Rana

Reference (section label): [class.conv.ctor]

Link to reflector thread (if any): Is default ctor a converting ctor

Issue description: Converting ctor in C++03 had to have at least one parameter. While C++11 changed this and stated that a ctor with more than one parameter can also be a converting ctor. In particular, according to C++11 as well as C++17:

A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.

Note that the above quoted reference does not say if a ctor with no parameter is a converting ctor. Then in C++17, the phrase if any was added:

A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters (if any) to the type of its class. Such a constructor is called a converting constructor.

Note the highlighted if any that was added in C++17. This seems to suggest that a default ctor such as C::C(){} is also a converting ctor.

Was this change intentional and needed for some particular code to work? I mean a ctor C::C(){} doesn't convert any parameter to the class type C so it doesn't make much sense to call it a converting constructor. So is a default constructor supposed to be a converting constructor.

This matters because the behavior of the following program depends on whether or not C::C() is also a converting ctor. We see implementation divergence for the following code.

struct A
{
  explicit A(int = 10);
  A()= default;
};

A a = {}; //msvc ok but gcc and clang fails here

The current wording seems to make this well-formed as described below. Not sure if this was the intended behavior.

First note that A a = {}; is copy-initialization.

  1. The initialization that occurs in the = form of a brace-or-equal-initializer or condition ([stmt.select]), as well as in argument passing, function return, throwing an exception ([except.throw]), handling an exception ([except.handle]), and aggregate member initialization ([dcl.init.aggr]), is called copy-initialization.

Next we move to the semantics of the initializer.

  1. The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression. If the initializer is not a single (possibly parenthesized) expression, the source type is not defined.
  • If the initializer is a (non-parenthesized) braced-init-list or is = braced-init-list, the object or reference is list-initialized ([dcl.init.list]).

The above means that, the object is to be list-initialized.

From list initialization:

List-initialization is initialization of an object or reference from a braced-init-list.
Such an initializer is called an initializer list, and the comma-separated initializer-clauses of the initializer-list or designated-initializer-clauses of the designated-initializer-list are called the elements of the initializer list.
An initializer list may be empty. List-initialization can occur in direct-initialization or copy-initialization contexts; list-initialization in a direct-initialization context is called direct-list-initialization and list-initialization in a copy-initialization context is called copy-list-initialization.

The above means that A a = {}; is copy-list initiaization. Next we see the effect of list initialization:

  1. List-initialization of an object or reference of type T is defined as follows:
  • Otherwise, if the initializer list has no elements and T is a class type with a default constructor, the object is value-initialized.

The above means that the object will be value initialized, so we move on to value-initialization:

  1. To value-initialize an object of type T means:
  • if T has either no default constructor ([class.default.ctor]) or a default constructor that is user-provided or deleted, then the object is default-initialized;

This means that the object will be default initialized:

  1. To default-initialize an object of type T means:
  • If T is a (possibly cv-qualified) class type ([class]), constructors are considered.
    The applicable constructors are enumerated ([over.match.ctor]), and the best one for the initializer () is chosen through overload resolution ([over.match]). The constructor thus selected is called, with an empty argument list, to initialize the object.

So we move on to over.match.ctor to get a list of candidate ctors. Also do note the initializer() part in the above quoted reference as it will be used at the end as an argument.

  1. When objects of class type are direct-initialized, copy-initialized from an expression of the same or a derived class type ([dcl.init]), or default-initialized, overload resolution selects the constructor. For direct-initialization or default-initialization that is not in the context of copy-initialization, the candidate functions are all the constructors of the class of the object being initialized. For copy-initialization, the candidate functions are all the converting constructors of that class. The argument list is the expression-list or assignment-expression of the initializer.

This means that only the non-explict ctor A::A() is the candidate because it is a converting ctor while the other explicit A::A(int) is not.

Finally, since we only have one viable option, it is the one that is selected for the initializer ().

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.