Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple implicit conversions on custom types not allowed?

class C {
public:
    C() { }
};

class B {
public:
    B(C c) { }
    B() { }
};

class A {
public:
    A(bool b) { }
    A(B b) { }
};

int main() {
    A a1 = true; // bool -> A        is allowed
    A a2 = B();  // B -> A           is allowed

    A a3 = 7;    // int -> bool -> A is allowed
    A a4 = C();  // C -> B -> A      isn't allowed
}

Why I can use two-step implicit conversion with bool but can't use it with C? What is the general rule describing multistep implicit conversion?

like image 674
Nelson Tatius Avatar asked Oct 11 '12 19:10

Nelson Tatius


People also ask

Which of the following types of conversions is implicit in C++?

Type Conversion in C++ Implicit Type Conversion Also known as 'automatic type conversion'. Done by the compiler on its own, without any external trigger from the user.

How do you avoid implicit conversions in C++?

Keyword explicit tells compiler to not use the constructor for implicit conversion. For example declaring Bar's constructor explicit as - explicit Bar(int i); - would prevent us from calling ProcessBar as - ProcessBar(10); .

What happens in implicit conversion?

An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.

Does C allow implicit conversion?

Implicit Type Conversion is also known as 'automatic type conversion'. It is done by the compiler on its own, without any external trigger from the user. It generally takes place when in an expression more than one data type is present.


2 Answers

There is no multi-step user-defined implicit conversion.

int -> bool -> A

is allowed because the int->bool conversion isn't user-defined.

12.3 Conversions [class.conv]

1 Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

2 User-defined conversions are applied only where they are unambiguous (10.2, 12.3.2). Conversions obey the access control rules (clause 11). Access control is applied after ambiguity resolution (3.4).

3 [ Note: See 13.3 for a discussion of the use of conversions in function calls as well as examples below. —end note ]

4 At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

like image 70
Luchian Grigore Avatar answered Nov 15 '22 17:11

Luchian Grigore


Since this construction is perfectly legal

A a4((C()));

problem is, that you use copy initization. Really, your example is equal to

A a4((A(C()));

8.5/16

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 destination type is a (possibly cv-qualified) class type:

— Otherwise (i.e., for the remaining copy-initialization cases), user-defined conversion sequences that can convert from the source type to the destination type or (when a conversion function is used) to a derived class thereof are enumerated as described in 13.3.1.4, and the best one is chosen through overload resolution (13.3).

13.3.1.4/1

Under the conditions specified in 8.5, as part of a copy-initialization of an object of class type, a user-defined conversion can be invoked to convert an initializer expression to the type of the object being initialized.

Overload resolution is used to select the user-defined conversion to be invoked. Assuming that “cv1 T” is the type of the object being initialized, with T a class type, the candidate functions are selected as follows: — The converting constructors (12.3.1) of T are candidate functions.

— When the type of the initializer expression is a class type “cv S”, the non-explicit conversion functions of S and its base classes are considered.

13.3.3.1/4

However, when considering the argument of a constructor or user-defined conversion function that is a candidate by 13.3.1.3 when invoked for the copying/moving of the temporary in the second step of a class copy-initialization, by 13.3.1.7 when passing the initializer list as a single argument or when the initializer list has exactly one element and a conversion to some class X or reference to (possibly cv-qualified) X is considered for the first parameter of a constructor of X, or by 13.3.1.4, 13.3.1.5, or 13.3.1.6 in all cases, only standard conversion sequences and ellipsis conversion sequences are considered.

Your user-defined conversion (C -> B) is not considered in this case.

like image 44
ForEveR Avatar answered Nov 15 '22 18:11

ForEveR