Are standard conversion sequences include explicit conversions? - c++

I am just trying to understand what does the standard mean by "standard conversion sequences"; and I have ended up with that "standard conversion sequences" are "sequences of standard implicit conversions". But I think that's not true for some contexts; for instance, from [expr.static.cast]/7:
[..] A program is ill-formed if it uses static_­cast to perform the inverse of an ill-formed standard conversion sequence.
struct B { };
struct D : private B { };
void f() {
static_cast<D*>((B*)0); // error: B is a private base of D
// ..
}
And General[conv.general]/1 states:
Standard conversions are implicit conversions with built-in meaning.
[..] A standard
conversion sequence is a sequence of standard conversions in the
following order:
[..]
(1.2) Zero or one conversion from the
following set: integral promotions, floating-point promotion, integral
conversions, floating-point conversions, floating-integral
conversions, pointer conversions, pointer-to-member conversions, and
boolean conversions.
[..]
As I know, I think that a standard conversion sequence is only implicit conversions not including any explicit conversion. I mean the above conversion (B*)0 is explicit pointer conversion, even though the standard said that this conversion is ill-formed standard conversion sequance.
So if my thinking is true, why is this explicit cast expression (B*)0 is said to be standard conversion sequence and it is an implicit conversion not explicit?
From this answer on a some question:
the standard conversion is a set of built-in rules the compiler can
apply when converting one type to another. Those built-in conversions
include:
No conversions
Lvalue-to-rvalue conversion
Array-to-pointer conversion
Function-to-pointer conversion
Qualification conversions
Integral promotions
Floating point promotion
Integral conversions
Floating point conversions
Floating-integral conversions
Pointer conversions
Pointer to member conversions
Boolean conversions
Given the conversions above, if those conversions are performed explicitly, do they still said to be standard conversion sequences?
In general, Are conversions performed explicitly (including C++ cast operators) said to be standard conversion sequences?

Related

Temporary materialization conversion not in a standard conversion sequence

Temporary materialization conversion is a standard conversion, see § 7.3 Standard Conversions; 7.3.4 [conv.rval]:
A prvalue of type T can be converted to an xvalue of type T.
This conversion initializes a temporary object ([class.temporary]) of type T from the prvalue by evaluating the prvalue with the temporary object as its result object, and produces an xvalue denoting the temporary object.
T shall be a complete type.
But why is it not mentioned in the list of standard conversion sequences?
See [conv]/1:
A standard conversion sequence is a sequence of standard conversions in the following order:
Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion, and function-to-pointer conversion.
Zero or one conversion from the following set: integral promotions, floating-point promotion, integral conversions, floating-point conversions, floating-integral conversions, pointer conversions, pointer-to-member conversions, and boolean conversions.
Zero or one function pointer conversion.
Zero or one qualification conversion.
Is it because an object would have to be created either way, and therefore would have no impact on determining whether a conversion sequence is better than another?
Is it because an object would have to be created either way, and therefore would have no impact on determining whether a conversion sequence is better than another?
Yes, temporary materialization is not a choice, so it's "free" and exempt from ICS ranking. It's applied when needed, see [expr.basic.lval]/7:
Whenever a prvalue appears as an operand of an operator that expects a glvalue for that operand, the temporary materialization conversion is applied to convert the expression to an xvalue.
For example, the dot-expression requires the left-hand side to be a glvalue:
struct X {
void func(int) { }
void func(long) { }
};
int n = 1;
X().func(n);
Here the X() prvalue must first become an xvalue (materialized) before we can proceed to .func(n), at which time ICS ranking comes into picture to decide how to invoke func(n), since there can be different conversion sequences leading to different alternatives.

Implicit conversion sequence

N3797 §13.3.3.1 [over.best.ics] says:
The sequence of conversions is an implicit conversion as defined in
Clause 4 [...]
However, clause 4 defines the following list of the conversions:
Lvalue-to-rvalue conversion
Array-to-pointer conversion
Function-to-pointer conversion
Qualification conversions
Integral promotions
Floating point promotion
Integral conversions
Floating point conversions
Floating-integral conversions
Pointer conversions
Pointer to member conversions
Boolean conversions
Integer conversion rank
Consider the following example:
#include <iostream>
using namespace std;
struct A
{
operator int()
{
return 42;
}
};
A a;
int b = a; //User-defined conversion sequence applied
int main() { }
As long as user-defined conversion doesn't belong to a set of standard conversions, there is no any standard conversion being applied in the example. So what is the sense of the quote I provided?
The rest of the quote you omitted might be illuminating:
§13.3.3.1/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).
Clause 4 does indeed talk about this.
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).
6 The effect of any implicit conversion is the same as performing the
corresponding declaration and initialization and then using the
temporary variable as the result of the conversion. The result is an
lvalue if T is an lvalue reference type or an rvalue reference to
function type (8.3.2), an xvalue if T is an rvalue reference to
object type, and a prvalue otherwise. The expression e is used as a
glvalue if and only if the initialization uses it as a glvalue.
The "full set of such conversions" (listed in Clause 4) refers to standard conversions. Remember that it says standard conversion sequences can be empty. Then §13.3.3.1.2 describes user-defined conversion sequences. It consists of:
A standard conversion sequence
A user-defined conversion
Another standard conversion sequence

Implicit conversion sequences?

N3797 §13.3.3.1 [over.best.ics] defines an implicit conversion sequence concept. More precisely, it says:
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).
The thing is Clause 4 doesn't concerned in user-defined conversions and ellipsis conversions, it only defines standard conversion. Since, the sentence The sequence of conversions is an implicit conversion as defined in Clause 4 isn't clear to me. How can the rules from the clause 4 ever be applied to all three conversion sequences. I mean
A well-formed implicit conversion sequence is one of the following
forms:
— a standard conversion sequence (13.3.3.1.1),
— a user-defined conversion sequence (13.3.3.1.2), or
— an ellipsis conversion sequence (13.3.3.1.3).

Second standard conversion sequence of user-defined conversion

I have a misunderstanding about standard-conversion sequence terms. I have come across the following quote N3797 §8.5.3/5 [dcl.init.ref]:
— If the initializer expression
— is an xvalue (but not a bit-field), class prvalue, array prvalue or
function lvalue and “cv1 T1” is reference-compatible with “cv2
T2”, or
— has a class type (i.e., T2 is a class type), where T1 is not
reference-related to T2, and can be converted to an xvalue, class
prvalue, or function lvalue of type “cv3 T3”, where “cv1 T1” is
reference-compatible with “cv3 T3” (see 13.3.1.6),
[..]
In the second case, if the reference is an rvalue reference and the second standard conversion sequence of the user-defined conversion
sequence includes an lvalue-to-rvalue conversion, the program is
ill-formed.
What is the second standard conversion sequence here? I thought there is a standard conversion sequence including all necessary standard conversions (user-defined and implicit).
[over.ics.user]:
A user-defined conversion consists of an initial standard conversion sequence followed by a user-defined conversion (12.3) followed by a second standard conversion sequence. […]
The second standard conversion sequence converts the result of the
user-defined conversion to the target type for the sequence.
E.g. for
struct A
{
operator int();
};
void foo(short);
foo(A());
The second standard conversion sequence converts the int prvalue to the parameter of foo, that is, short. The first standard conversion sequence converts the A object to A (the implicit object parameter of operator int), which constitutes an identity conversion. For references, the rule quoted by you provides an example:
struct X {
operator B();
operator int&();
} x;
int&& rri2 = X(); // error: lvalue-to-rvalue conversion applied to
// the result of operator int&
Here, operator int& is selected by overload resolution. The return value is an lvalue reference to int. For that to initialize the reference, an lvalue-to-rvalue conversion would be necessary, and that's precisely what the quote prevents: Lvalues shall not be bound to rvalue references.
What the standard conversion term means is covered in the following clause of the C++ Standard:
4 Standard conversions [conv]
Standard conversions are implicit conversions with built-in meaning. Clause 4 enumerates the full set of such conversions. A standard conversion sequence is a sequence of standard conversions in the following order:
— Zero or one conversion from the following set: lvalue-to-rvalue conversion, array-to-pointer conversion,
and function-to-pointer conversion.
— Zero or one conversion from the following set: integral promotions, floating point promotion, integral conversions, floating point conversions, floating-integral conversions, pointer conversions, pointer to member conversions, and boolean conversions.
— Zero or one qualification conversion.
[ Note: A standard conversion sequence can be empty, i.e., it can consist of no conversions. — end note ]
A standard conversion sequence will be applied to an expression if necessary to convert it to a required
destination type.
In other words, the standard conversion is a set of built-in rules the compiler can apply when converting one type to another. Those built-in conversions include:
No conversions
Lvalue-to-rvalue conversion
Array-to-pointer conversion
Function-to-pointer conversion
Qualification conversions
Integral promotions
Floating point promotion
Integral conversions
Floating point conversions
Floating-integral conversions
Pointer conversions
Pointer to member conversions
Boolean conversions
The standard conversion sequence can appear twice during the user-defined conversion sequence - either before and/or after the user-defined conversion:
§ 13.3.3.1.2 User-defined conversion sequences [over.ics.user]
A user-defined conversion sequence consists of an initial standard conversion sequence followed by a user-defined conversion (12.3) followed by a second standard conversion sequence. If the user-defined conversion is specified by a constructor (12.3.1), the initial standard conversion sequence converts the source type to the type required by the argument of the constructor. If the user-defined conversion is specified by a conversion function (12.3.2), the initial standard conversion sequence converts the source type to the implicit object parameter of the conversion function.
The second standard conversion sequence converts the result of the user-defined conversion to the target type for the sequence. Since an implicit conversion sequence is an initialization, the special rules for initialization by user-defined conversion apply when selecting the best user-defined conversion for a user-defined conversion sequence (see 13.3.3 and 13.3.3.1).
Having that said, for the following conversion:
A a;
B b = a;
the compiler will search for the conversion constructor in B that can take an instance of A (source type) through some initial standard conversion sequence so that it could then perform that user-defined conversion through selected constructor, and then apply another standard conversion - second standard conversion - for converting the resultant type of the user-defined conversion to the target type;
or:
the compiler will search for the conversion function in A that is callable after some initial standard conversion sequence of the implicit context, that could then convert an instance of A to some type convertible through another standard conversion - the second standard conversion - to the target type B.
As a tangible example let's consider the below conversion:
struct A
{
operator int() const;
};
A a;
bool b = a;
The compiler considers the following user-defined conversion sequence:
Initial standard conversion: Qualification conversion of A* to const A* to call const-qualified operator int() const.
User-defined conversion: conversion of A to int, through user-defined conversion function.
Second standard conversion: Boolean conversion of int to bool.
The case you are asking about can be split as follows:
struct A
{
operator int&();
};
int&& b = A();
The source type is A.
The target type is int&&.
The user-defined conversion sequence is the conversion of A to int&&.
The initial standard conversion sequence is No conversion at all.
The user-defined conversion is the conversion of A to int&.
The second standard conversion sequence (converting the result of the user-defined conversion to the target type) that is a part of the overall user-defined conversion sequence would be here the standard conversion of int& to int&& - an Lvalue-to-rvalue conversion. That conversion is considered since int& and int&& are reference-compatible types. According to the below statement §8.5.3 [dcl.init.ref]/p5:
[...] if the reference is an rvalue reference and the second standard conversion sequence of the user-defined conversion sequence includes an lvalue-to-rvalue conversion, the program is ill-formed.
that conversion is not applicable in the overall user-defined conversion sequence.

operator[](const char *) ambiguity

The following code
#include <string>
struct Foo {
operator double() {
return 1;
}
int operator[](std::string x) {
return 1;
}
};
int main() {
Foo()["abcd"];
}
Compiles fine with g++ but fails with clang and intel compilers because of an ambiguity between the declared method and native operator [].
It would be clear for me if Foo had an implicit conversion to int, but here the conversion is to double. Doesn't that solve the ambiguity?
§13.3.3.1.2 [over.ics.user]/p1-2:
A user-defined conversion sequence consists of an initial standard
conversion sequence followed by a user-defined conversion (12.3)
followed by a second standard conversion sequence. If the user-defined
conversion is specified by a constructor (12.3.1), the initial
standard conversion sequence converts the source type to the type
required by the argument of the constructor. If the user-defined
conversion is specified by a conversion function (12.3.2), the initial
standard conversion sequence converts the source type to the implicit
object parameter of the conversion function.
The second standard conversion sequence converts the result of the
user-defined conversion to the target type for the sequence.
In particular, there's an implicit conversion from floating point to integral type (§4.9 [conv.fpint]/p1):
A prvalue of a floating point type can be converted to a prvalue of an
integer type. The conversion truncates; that is, the fractional part
is discarded. The behavior is undefined if the truncated value cannot
be represented in the destination type.
For overload resolution purposes, the applicable candidates are:
Foo::operator[](std::string x) // overload
operator[](std::ptrdiff_t, const char *); // built-in
Given an argument list of types (Foo, const char [5]).
To match the first operator function, the first argument is an exact match; the second requires a user-defined conversion.
To match the second built-in function, the first argument requires a user-defined conversion sequence (the user-defined conversion to double followed by a standard conversion to std::ptrdiff_t, a floating-integral conversion). The second argument requires a standard array-to-pointer conversion (still exact match rank), which is better than a user-defined conversion.
Thus for the first argument the first function is better; for the second argument the second function is better, we have a criss-cross situation, overload resolution fails, and the program is ill-formed.
Note that, while for the purposes of operator overload resolution, a user-defined conversion sequence can have two standard conversion sequences (one before and one after the user-defined conversion), and operands of non-class-type can be converted to match the candidates, if a built-in operator is selected, the second standard conversion sequence is not applied for operands of class type, and no conversion at all is applied for operands for non-class type before the operator is interpreted as a built-in (§13.3.1.2 [over.match.oper]/p7):
If a built-in candidate is selected by overload resolution, the
operands of class type are converted to the types of the corresponding
parameters of the selected operation function, except that the second
standard conversion sequence of a user-defined conversion sequence
(13.3.3.1.2) is not applied. Then the operator is treated as the
corresponding built-in operator and interpreted according to Clause 5.
Thus if Foo::operator[](std::string x) is removed, the compiler should report an error, though clang doesn't. This is an obvious clang bug, as it fails to reject the example given in the standard.