Implicit conversion with multiple intermediate conversion steps [duplicate] - c++

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?

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.

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.

Related

Which of two conversion operators must be selected by C++ compiler?

A class can declare several conversion operators. In particular it can be conversion operators to some type and to const-reference of the same type. Which of the two conversion operators must be selected in case of requested conversion to that type?
Consider an example:
#include <iostream>
struct B {};
static B sb;
struct A {
operator B() { std::cout << "operator B() "; return sb; }
operator const B &() { std::cout << "operator const B &() "; return sb; }
};
int main() {
A a;
[[maybe_unused]] B b(a);
}
Here Clang selects operator B(), MSVC selects operator const B &(), and GCC complains about ambiguity of the selection:
<source>:13:27: error: call of overloaded 'B(A&)' is ambiguous
13 | [[maybe_unused]] B b(a);
| ^
<source>:3:8: note: candidate: 'constexpr B::B(const B&)'
3 | struct B {};
| ^
<source>:3:8: note: candidate: 'constexpr B::B(B&&)'
Demo: https://gcc.godbolt.org/z/874h7h3d1
Which of the compilers is right?
The program is ill-formed and rejected by GCC is correct here but the diagnosis can arguably say it is not completely correct. For this declaration B b(a);, it is direct-initialization of an object of class B from the initializer a of type A, according to [over.match.copy] p1
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 of T are candidate functions.
When the type of the initializer expression is a class type “cv S”, conversion functions are considered. The permissible types for non-explicit conversion functions are T and any class derived from T. When initializing a temporary object ([class.mem]) to be bound to the first parameter of a constructor where the parameter is of type “reference to cv2 T” and the constructor is called with a single argument in the context of direct-initialization of an object of type “cv3 T”, the permissible types for explicit conversion functions are the same; otherwise there are none.
For converting constructors, they are copy/move constructors of B, however, [over.best.ics#general-4] prohibits the user-defined conversion sequence to apply to the target to match the parameter of the constructor
However, if the target is
the first parameter of a constructor or
[...]
and the constructor or user-defined conversion function is a candidate by
[...]
[over.match.copy], [over.match.conv], or [over.match.ref] (in all cases), or
[...]
user-defined conversion sequences are not considered.
Hence, the copy/move constructors of B are not viable functions. The ambiguity arises from the viable functions A::operator B() and A::operator const B &(), since the implicit parameter objects of them both have type A& and the corresponding argument is an lvalue of type A, hence neither is better than the other. Hence, the only opportunity that can determine which is better falls on [over.match.best#general-2.2]
the context is an initialization by user-defined conversion (see [dcl.init], [over.match.conv], and [over.match.ref]) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type.
The second standard conversion sequences of them are both identity conversions, hence they are not indistinguishable. So, the result is ambiguity. GCC is merely correct in that the program is ambiguous, but, obviously, its diagnosis has a bit misleading. Since the copy/move constructors are not viable functions in this case at all, how could they cause the ambiguity? If we suppress the production of the defaulted move constructor, GCC and Clang are both incorrect here, which is back to this question you have referred.

Is the copy-list-initialization for class object a user-defined conversion

#include <iostream>
struct Data{
Data(int){
}
}
int main(){
Data d = {0}; //#1
}
As the above code show,Does the #1 invocation contain a user-defined conversion?In my understanding about the standard ,I think it does not
For copy-list-initialization rules [dcl.init.list]
Otherwise, if T is a class type, constructors are considered. The applicable constructors are enumerated and the best one is chosen through overload resolution ([over.match], [over.match.list]). If a narrowing conversion (see below) is required to convert any of the arguments, the program is ill-formed
[over.match.list]
If no viable initializer-list constructor is found, overload resolution is performed again, where the candidate functions are all the constructors of the class T and the argument list consists of the elements of the initializer list
The standard only said the best match constructor is used to initialize the object which is initialized by using the element of initializer list,it is different with copy-initialization(the copy-initialization say that "user-defined conversion sequences that can convert from the source type to the destination type",explicit define the copy-initialization need a user-defined conversion)
So Data d = {0}; => Data d(0); there's no user-defined conversion other than standard conversions?Is my understanding right?
However another terms [class.conv]
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 [conv]), for initialization, and for explicit type conversions
the above term means if the initialized destination type is class type and need to use constructors or conversion functions,then the conversions are "user-defined conversions"
I'm confused by these terms,what actually the Data d = {0}; is a user-defined conversion or not?
Type conversions of class objects can be specified by constructors and by conversion functions.
User-defined conversion is first a type conversion. In the initialization Data d = {0};, there is even no type conversion, thus no user-defined conversion.

Reference binding through ambiguous conversion operator

#include <iostream>
using namespace std;
struct CL2
{
CL2(){}
CL2(const CL2&){}
};
CL2 cl2;
struct CL1
{
CL1(){}
operator CL2&(){cout<<"operator CL2&"; return cl2;}
operator const CL2&(){cout<<"operator const CL2&"; return cl2;}
};
CL1 cl1;
int main()
{
CL1 cl1;
CL2 cl2 (cl1);
}
Both clang and gcc give ambiguous conversion operator, but Visual Studio compiles ok and prints "operator const CL2&". How must be right according to Standard?
As I undestand, conversion of CL1 to const CL2& is in copy-initialization context (as a part of a direct-initialization of cl2 object). I seen n4296 draft, [over.match.copy]:
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. When initializing a temporary to be bound
to the first parameter of a constructor where the parameter is of type
“reference to possibly cv-qualified T” and the constructor is called
with a single argument in the context of direct-initialization of an
object of type “cv2 T”, explicit conversion functions are also
considered. Those that are not hidden within S and yield a type whose
cv-unqualified version is the same type as T or is a derived class
thereof are candidate functions. Conversion functions that return
“reference to X” return lvalues or xvalues, depending on the type of
reference, of type X and are therefore considered to yield X for this
process of selecting candidate functions.
I.e. both of conversion operators are considered as return CL2 and const CL2 (not just CL2 without const) and it remains to solve, which conversion is better: CL2 -> const CL2& or const CL2 -> const CL2&. The second case seems more appropriate. Should a better qualification conversion considered in that context? Or both cases are Identity conversion? I couldn't find it in Standard
Since both conversion operators have identical signatures, the only way in which one could be preferred over the other is by application of [over.match.best]/(1.4)…
— the context is an initialization by user-defined conversion (see 8.5,
13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the
entity being initialized) is a better conversion sequence than the
standard conversion sequence from the return type of F2 to the
destination type.
…or (1.5):
— the context is an initialization by conversion function for direct
reference binding (13.3.1.6) of a reference to function type, […]
Clearly, neither applies, hence the ambiguity. A possible way to disambiguate:
operator CL2&();
operator const CL2&() const;
Demo; Here, the former overload's initial standard conversion sequence of the implicit object argument is better as per [over.ics.rank]/(3.2.6), which is decisive by [over.match.best]/(1.3).

Should initialization by conversion function be ambiguous when two candidates have the same cv-qualification?

Both clang and gcc accept the following code and choose A::operator B*.
struct B
{
};
struct A : B
{
operator A*();
operator B*();
};
A a;
void* x = a;
My reading of the standard - specifically sentences highlighted below in bold - suggests that this conversion should be ambiguous.
Both A::operator A* and A::operator B* are candidates for overload resolution because A* and B* are both convertible to void* via a standard conversion. Because the implied object parameter A& is the only argument, only the conversion sequence that converts from the implied object argument to the implied object parameter is considered - the type yielded by the conversion function is ignored. In both cases, the implied object argument is the initializer expression's type A, and the implied object parameter is A&. If both conversion sequences are identical, there is no way to distinguish between the two candidates.
8.5 Initializers [dcl.init]
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 destination type is a [reference/array/class...] [deleted details not applicable to this scenario]
— Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered.
The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload
resolution (13.3). The user-defined conversion so selected is called to convert the initializer
expression into the object being initialized. If the conversion cannot be done or is ambiguous, the
initialization is ill-formed.
13.3.1.5 Initialization by conversion function [over.match.conv]
Under the conditions specified in 8.5, as part of an initialization of an object of nonclass type, a conversion
function can be invoked to convert an initializer expression of class type to the type of the object being
initialized. Overload resolution is used to select the conversion function to be invoked. Assuming that “cv1
T” is the type of the object being initialized, and “cv S” is the type of the initializer expression, with S a
class type, the candidate functions are selected as follows:
— The conversion functions of S and its base classes are considered. Those non-explicit conversion
functions that are not hidden within S and yield type T or a type that can be converted to type T
via a standard conversion sequence (13.3.3.1.1) are candidate functions. For direct-initialization, those
explicit conversion functions that are not hidden within S and yield type T or a type that can be
converted to type T with a qualification conversion (4.4) are also candidate functions. Conversion
functions that return a cv-qualified type are considered to yield the cv-unqualified version of that type
for this process of selecting candidate functions. Conversion functions that return “reference to cv2
X” return lvalues or xvalues, depending on the type of reference, of type “cv2 X” and are therefore
considered to yield X for this process of selecting candidate functions.
The argument list has one argument, which is the initializer expression. [ Note: This argument will be
compared against the implicit object parameter of the conversion functions. —end note ]
Is this ambiguous according to the standard?
EDIT: note that this is a similar question, but not the same as Distinguishing between user-defined conversion sequences by the initial standard conversion sequence
The difference being that in my example both conversion functions have the same qualification.
TLDR: When everything else is equal, overload resolution breaks the tie by which conversion function has the best conversion from its return value to the target type.
All references are to ISO/IEC 14882:2011 (C++11). The behavior of the initialization:
void* x = a;
is defined as follows. First, this is an initialization as described in 8.5 Initializers [dcl.init] and conforms to the grammar described in p1. Since the destination type void* is a non-class type, and the source type A is a class type, this specific initializer is of the form described in 8.5 p16, bullet 7:
Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered. The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into the object being initialized. If the conversion cannot be done or is ambiguous, the initialization is ill-formed.
The "enumeration of applicable conversion functions" is detailed in 13.3.1.5 p1:
Under the conditions specified in 8.5, as part of an initialization of an object of nonclass type, a conversion
function can be invoked to convert an initializer expression of class type to the type of the object being
initialized. Overload resolution is used to select the conversion function to be invoked. Assuming that “cv1
T” is the type of the object being initialized, and “cv S” is the type of the initializer expression, with S a
class type, the candidate functions are selected as follows:
The conversion functions of S and its base classes are considered. Those non-explicit conversion
functions that are not hidden within S and yield type T or a type that can be converted to type T
via a standard conversion sequence (13.3.3.1.1) are candidate functions. For direct-initialization, those
explicit conversion functions that are not hidden within S and yield type T or a type that can be
converted to type T with a qualification conversion (4.4) are also candidate functions. Conversion
functions that return a cv-qualified type are considered to yield the cv-unqualified version of that type
for this process of selecting candidate functions. Conversion functions that return “reference to cv2
X” return lvalues or xvalues, depending on the type of reference, of type “cv2 X” and are therefore
considered to yield X for this process of selecting candidate functions.
Note that both A::operator A*() and A::operator B*() are candidate functions, since both A* and B* are convertible to void* per
4.10p2: "A prvalue of type “pointer to cv T,” where T is an object type, can be converted to a prvalue of type “pointer
to cv void”." Given that both functions are candidates, overload resolution must choose between them.
Overload resolution is decribed in 13.3 [over.match]. p2 states:
Overload resolution selects the function to call in seven distinct contexts within the language:
...
invocation of a conversion function for initialization of an object of a nonclass type from an expression of class type (13.3.1.5)
...
Each of these contexts defines the set of candidate functions and the list of arguments in its own unique way. But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:
First, a subset of the candidate functions (those that have the proper number of arguments and meet certain other conditions) is selected to form a set of viable functions (13.3.2).
Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.
Which of our two functions are viable? 13.3.2 [over.match.viable] p1:
From the set of candidate functions constructed for a given context (13.3.1), a set of viable functions is
chosen, from which the best function will be selected by comparing argument conversion sequences for the
best fit (13.3.3).
The requirements are presented in p2:
First, to be a viable function, a candidate function shall have enough parameters to agree in number with
the arguments in the list.
and p3:
Second, for F to be a viable function, there shall exist for each argument an implicit conversion sequence
(13.3.3.1) that converts that argument to the corresponding parameter of F.
Both requirements are trivially met by our conversion functions: they have a single (implicit) argument of the same type as the initializer expression a.
Determination of the best of the viable functions is described in 13.3.3 [over.match.best]. It defines some formalisms for describing conversion sequences, sequences of operations necessary to convert from the types of the actual function arguments to the types of the formal function parameters. In the case of our conversion functions, they both have exactly one parameter whose type is exactly that of the actual argument, so the "conversion sequence" corresponding to each overload is the identity sequence. They are discriminated by the language in p1:
Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then
for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,
the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the
standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the
entity being initialized) is a better conversion sequence than the standard conversion sequence from
the return type of F2 to the destination type.
What about that final bullet? Does one of our overloads have a better standard conversion sequence from its return type to void*?
13.3.3.2 Ranking Implicit Conversion Sequences [over.ics.rank] p4 states in the second bullet point:
If class B is derived directly or indirectly from class A, conversion of B* to A* is better than conversion of B* to void*, and conversion of A* to void* is better than conversion of B* to void*.
This is exactly the case of the OP, except with the names A and B reversed. Overload resolution on the two conversion operators of the OP is resolved in favor of A::operator B*() since the cited rule makes the conversion sequence B* → void* better than A* → void*

Explicit conversion functions, direct-initialization, and converting constructors

Post-standard draft n3376 has as an example (12.3.2:2) of the use of an explicit conversion function to a user-defined type:
class Y { };
struct Z {
explicit operator Y() const;
};
void h(Z z) {
Y y1(z); // OK: direct-initialization
}
Per 12.3.2:2, an explicit conversion function is "only considered as a user-defined conversion for direct-initialization"; however, that would appear to permit:
struct Y { Y(int); };
struct Z {
explicit operator int() const;
};
void h(Z z) {
Y y1(z); // direct-initialization
}
which appears to conflict with the intent of the standard, and indeed is rejected by gcc-4.7.1:
source.cpp: In function 'void h(Z)':
source.cpp:4:9: error: no matching function for call to 'Y::Y(Z&)'
source.cpp:4:9: note: candidates are:
source.cpp:1:12: note: Y::Y(int)
source.cpp:1:12: note: no known conversion for argument 1 from 'Z' to 'int'
source.cpp:1:8: note: constexpr Y::Y(const Y&)
source.cpp:1:8: note: no known conversion for argument 1 from 'Z' to 'const Y&'
source.cpp:1:8: note: constexpr Y::Y(Y&&)
source.cpp:1:8: note: no known conversion for argument 1 from 'Z' to 'Y&&'
Is gcc correct to reject the conversion from Z to Y via int, or does the standard indeed permit this usage?
I considered the context of the mentioned direct-initialization; per the definition of direct-initialization to class type in 8.5:16, a constructor is called with the initializer expression as its arguments, which therefore are converted to the parameter type by an implicit conversion sequence (13.3.3.1). Since an implicit conversion sequence is an implicit conversion (4:3), and thus models copy-initialization (8.5:14) and not direct-initialization, the language in 12.3.2:2 must be referring to the expression as a whole.
Note also that this isn't a violation of 12.3:4 (multiple user-defined conversions); the same compiler is happy with the same code with explicit removed (as are Clang and Comeau):
struct Y { Y(int); };
struct Z { operator int(); };
void h(Z z) {
Y y1(z); // direct-initialization
}
I think Jesse Good has identified the distinction between the operator Y and operator int cases in 13.3.1.4:1, but there's a third case that I'm still concerned by:
struct X {};
struct Y { Y(const X &); };
struct Z {
explicit operator X() const;
};
void h(Z z) {
Y y1(z); // direct-initialization via class-type X
}
The initialization of the temporary X to be bound to the single const X & parameter of the constructor of Y proceeds in a direct-initialization context per 13.3.1.4:1, with T as X and S as Z. I think this clause is incorrect and should read:
13.3.1.4 Copy-initialization of class by user-defined conversion [over.match.copy]
1 - [...] When initializing a temporary to be bound to the first parameter
of a constructor that takes a reference to possibly cv-qualified T as its first argument, called with a single argument in the context of direct-initialization of an object of type "cv2 T", explicit conversion functions are also considered. [...]
For the avoidance of confusion, I think 12.3.2:2 should also be amended:
12.3.2 Conversion functions [class.conv.fct]
2 - A conversion function may be explicit (7.1.2), in which case it is only considered as a user-defined conversion for direct-initialization (8.5) in certain contexts (13.3.1.4, 13.3.1.5, 13.3.1.6). [...]
Any comments on the above?
According to 8.5 and 13.3.1.3 the constructors of Y are considered and the best one is picked via overload resolution. In this case the relevant constructors are Y(int); and the copy and move constructors. In the process of overload resolution 13.3.2 Viable functions [over.match.viable] specifies this:
3 Second, for F to be a viable function, there shall exist for each argument an implicit conversion sequence (13.3.3.1) that converts that argument to the corresponding parameter of F. [...]
For all those constructors there is no such conversion from Z to either int or one of the flavours of Y. To convince ourselves, let's investigate what the Standard says about implicit conversion sequences in 13.3.3.1 Implicit conversion sequences [over.best.ics]:
1 An implicit conversion sequence is a sequence of conversions used to convert an argument in a function call to the type of the corresponding parameter of the function being called. The sequence of conversions is an implicit conversion as defined in Clause 4, which means it is governed by the rules for initialization of an object or reference by a single expression (8.5, 8.5.3).
If we cross-reference Clause 4, then we learn that an implicit conversion is defined in terms of copy-initialization (i.e. T t=e;, where T is int and e is z):
(§4.3) An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed, for some invented temporary variable t (8.5). [...]
So I take 12.3.2:2 not to apply for this initialization, which happens in the larger context of a direct initialization. Doing otherwise would contradict with this latest paragraph.
As noted in Luc Danton's answer, implicit conversion is defined in terms of copy initialization. Then, if we look at 13.3.1.4:1[Copy-initialization of class by user-defined conversion]:
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. When initializing a temporary to be bound to the first
parameter of a constructor that takes a reference to possibly
cv-qualified T as its first argument, called with a single argument in
the context of direct-initialization, explicit conversion functions
are also considered. Those that are not hidden within S and yield a
type whose cv-unqualified version is the same type as T or is a
derived class thereof are candidate functions. Conversion functions
that return “reference to X” return lvalues or xvalues, depending on
the type of reference, of type X and are therefore considered to yield
X for this process of selecting candidate functions.
If I understand this correctly, the first one works because the conversion function yields a Y and is therefore a candidate function as noted by the second emphasized part in the quote, however, in your second case, the set of candidate functions is empty because there is no conversion function to Y and no non-explicit conversion functions as noted by the first emphasized part.
Concerning the third case:
After finding defect report 1087, it seems clear that the intention was to allow, copy, move and template constructors when direct-initializing an object of cv2 T as you mention. If you read the first passage of 13.3.1.4, it says Assuming that “cv1 T” is
the type of the object being initialized, with T a class type, so I think that implies of an object of type "cv2 T" that you mention. However, (after reading it over), it seems that the change due to the defect report has caused the wording to become vague and not cover the third case you propose.
I am no language lawyer, however the wording of the standard implies to me that marking a conversion operator as explicit requires that you explicity specify the conversion type (i.e. int) as part of the initialisation of object y1. With the code Y y1(z), it would appear that you're relying on an implicit conversion, since the type you specify for variable y1 is Y.
Therefore, I would expect correct usage of the explicit conversion operator in this situation to be:
Y y1( int(z) );
Or, since you are effectively specifying a cast, preferably
Y y1( static_cast<int> (z) );