C++ explicit conversion and implicit conversion - c++

Look at the following two ways to create a new object of class Y:
(1)
X x;
Y y(x);//explicit conversion
(2)
X x;
Y y = x;//implicit conversion
The first way uses explicit conversion and another uses implicit conversion.But,I don't very understand how they work.What is their difference?Could someone interpret for me?The more detailed,the better.Thanks a lot.

The first is called direct-initialization while the second is called copy-initialization. Assuming that Y has a constructor that takes a X (or reference to it), direct-initiazliation will call that constructor directly and regardless of whether the constructor is marked as implicit. copy-initialization semantically is equivalent to:
Y y( implicit_conversion<Y>(x) );
That is, the argument is converted by means of an implicit conversion to the destination type and then the copy constructor is called to initialize the variable. In real life, the compiler will remove the copy and convert in place of the destination variable, but the compiler must check that there is an implicit conversion from X to Y, and the copy constructor is accessible.

Actually, both are implicit conversions assuming that your class "Y" has a constructor like:
public:
Y(X &x)
A class constructor with a single argument will perform the conversion for you.
To avoid implicit construction, use one of the following (one may be better for you based on your situation):
Don't declare a constructor with a single argument
Use the explicit keyword on the constructor declaration
Use an intermediate class (in other words only allow 'Y' to be initialized by 'Z', a class that never be assigned directly to 'Y')
Use a static member function to explicitly 'make' an instance of 'Y' using an 'X' (since the member function is not associated with an instance of the class

Related

Understanding copy-initialisation and implicit conversions

I am having trouble understanding why the following copy-initialization doesn't compile:
#include <memory>
struct base{};
struct derived : base{};
struct test
{
test(std::unique_ptr<base>){}
};
int main()
{
auto pd = std::make_unique<derived>();
//test t(std::move(pd)); // this works;
test t = std::move(pd); // this doesn't
}
A unique_ptr<derived> can be moved into a unique_ptr<base>, so why does the second statement work but the last does not? Are non-explicit constructors not considered when performing a copy-initialization?
The error from gcc-8.2.0 is:
conversion from 'std::remove_reference<std::unique_ptr<derived, std::default_delete<derived> >&>::type'
{aka 'std::unique_ptr<derived, std::default_delete<derived> >'} to non-scalar type 'test' requested
and from clang-7.0.0 is
candidate constructor not viable: no known conversion from 'unique_ptr<derived, default_delete<derived>>'
to 'unique_ptr<base, default_delete<base>>' for 1st argument
Live code is available here.
A std::unique_ptr<base> is not the same type as a std::unique_ptr<derived>. When you do
test t(std::move(pd));
You call std::unique_ptr<base>'s conversion constructor to convert pd into a std::unique_ptr<base>. This is fine as you are allowed a single user defined conversion.
In
test t = std::move(pd);
You are doing copy initialization so so you need to convert pd into a test. That requires 2 user defined conversions though and you can't do that. You first have to convert pd to a std::unique_ptr<base> and then you need to convert it to a test. It's not very intuitive but when you have
type name = something;
whatever something is needs to be only a single user defined conversion from the source type. In your case that means you need
test t = test{std::move(pd)};
which only uses a single implicit user defined like the first case does.
Lets remove the std::unique_ptr and look at in a general case. Since std::unique_ptr<base> is not the same type as a std::unique_ptr<derived> we essentially have
struct bar {};
struct foo
{
foo(bar) {}
};
struct test
{
test(foo){}
};
int main()
{
test t = bar{};
}
and we get the same error because we need to go from bar -> foo -> test and that has one user defined conversion too many.
The semantics of initializers are described in [dcl.init] ΒΆ17. The choice of direct initialization vs copy initialization takes us into one of two different bullets:
If the destination type is a (possibly cv-qualified) class type:
[...]
Otherwise, if the initialization is direct-initialization, or if it is copy-initialization where the cv-unqualified version of the source
type is the same class as, or a derived class of, the class of the
destination, constructors are considered. The applicable constructors
are enumerated ([over.match.ctor]), and the best one is chosen through
overload resolution. The constructor so selected is called to
initialize the object, with the initializer expression or
expression-list as its argument(s). If no constructor applies, or the
overload resolution is ambiguous, the initialization is ill-formed.
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
[over.match.copy], and the best one is chosen through overload
resolution. If the conversion cannot be done or is ambiguous, the
initialization is ill-formed. The function selected is called with the
initializer expression as its argument; if the function is a
constructor, the call is a prvalue of the cv-unqualified version of
the destination type whose result object is initialized by the
constructor. The call is used to direct-initialize, according to the
rules above, the object that is the destination of the
copy-initialization.
In the direct initialization case, we enter the first quoted bullet. As detailed there, constructors are considered and enumerated directly. The implicit conversion sequence that is required is therefore only to convert unique_ptr<derived> to a unique_ptr<base> as a constructor argument.
In the copy initialization case, we are not directly considering constructors anymore, but rather trying to see which implicit conversion sequence is possible. The only one available is unique_ptr<derived> to a unique_ptr<base> to a test. Since an implicit conversion sequence can contain only one user defined conversion, this is not allowed. As such the initialization is ill-formed.
One could say that using direct initialization sort of "bypasses" one implicit conversion.
Pretty sure that only single implicit conversion is allowed to be considered by the compiler. In first case only conversion from std::unique_ptr<derived>&& to std::unique_ptr<base>&& is required, in the second case the base pointer would also need to be converted to test (for default move constructor to work).
So for example converting the derived pointer to base: std::unique_ptr<base> bd = std::move(pd) and then move assigning it would work as well.

Confused between a copy constructor and a converting constructor

Since I have doubts about this question (for C++03) I am posting it here.I just read about conversion constructors and it states that
"To be a converting constructor, constructor must have single
argument and be declared without keyword explicit."
Now my question is whether the copy constructor can be called a conversion constructor provided it is not explicitly declared ? Does it qualify to be one ?
I believe it cant be called a conversion constructor because it only accepts the same type parameter ths resulting in no conversion. For Instance
foo a;
foo b;
a = 100; //a Conversion constructor would be called (i.e) foo(int a){...}
a = b ; //Since both objects are same type and have been initialized the assignment operator will be called (if there is an overloaded version otherwise the default will be called)
Is my understanding correct ?
Quoting the Standard:
[class.conv.ctor]/3
A non-explicit copy-constructor (12.8) is a converting constructor. An implicitly-declared copy constructor is not an explicit constructor; it may be called for implicit type conversions.
So yes, a copy-ctor is a converting ctor.
Also note [conv]/1 which specifies and points out in a remark:
Note: a standard conversion sequence can be empty, i.e., it can consist of no conversions.
and in /3:
An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed
So the set of implicit conversions contain the empty conversions.
Yes, a copy constructor is what it is -- a copy constructor. Which isn't a conversion constructor that converts from one type to a different type.

please explain this c++ syntax

could someone please explain the syntax of the following snippet from a c++ class template?
public:
explicit Foo(size_t ratio = 500)
:list(Bar<I>())
,vec(Bar<iterator>())
,n(0), r(ratio){}
I have decent experience with programming and understand most concepts but the syntax behind this is just so foreign to me, i can't understand it. I is the generic type. Specifically, I'm not sure what the explicit is doing here, in addition to what is going on when one would execute some code such as Foo<int> myfoo;.
thanks!
The explicit keyword makes sure that your constructor is not picked as part as a user-defined conversion sequence to perform implicit conversions when copy-initialized with a value of type size_t.
Without the explicit keyword, for instance, all of the following would be valid:
Foo<int> bar(Foo<int> f)
{
return 0; // OK
}
Foo<int> f = 1729; // OK
bar(42); // OK
Declaring your constructor as explicit prevents the initializations above from compiling.
What follows the constructor's signature is an initialization list, and it is used to construct the base class subobjects and data member subobjects of your class before the body of your constructor is entered.
When you do not use an initialization list, the data members of your class are default-constructed. This, however, may not be an option if your class has const data members, or data members of reference type, or data members of a class type which do not have a default constructor.
This is a constructor for the class Foo, but I'm sure you already knew that.
explicit says that this constructor must receive an argument of size_t. That is, one cannot pass in anything that would be implicitly casted to a type size_t (ex: int).
The rest of the things are part of the constructor's initializer list, which means the constructor initializes the data member list with Bar<I>(), etc.
This is the definition of a constructor for Foo. The constructor is explicit, which means that it won't be involved in implicit conversions. As an example consider:
void bar(Foo);
bar(10); // Error - would require an implicit conversion
Marking a constructor as explicit prevents such conversions.
Everything after the : is a member initialization list. It lists members of Foo by their names and the parentheses contain the expressions with which to initialize them. For example, list will be initialized with the temporary object created by Bar<I>(), n is initialized with 0, etc.

Explicit Call to a Constructor

I know the concept that we can call the Constructor both Explicitly and Implicitly, and i have tested both the scenarios(generally till now my all purposes got fulfilled by calling constructor Implicitly), but i was wondering that constructor get called implicitly whenever we create objects, so what is the main reason behind calling the constructor Explicitly. What advantage or disadvantage it provides when we call constructor Explicitly over the Implicit Call?
Example
class integer
{
int m ,n;
public:
integer (int x , int y);
};
integer :: integer (int x , int y )
{
m=x; n = y;
}
Now if i call like
integer int1 = integer( 0 , 100); // Explicit Call
integer int1(1,100); // implicit call
There are two different problems here, as your definition of explicit and implicit does not match the standard definition (on which most of the existing answers are based, being written before you added your example containing your own definition of explicit and implicit).
Ok so let's first consider your definition of explicit, which would be (I guess you call it explicit because you explicitly write the type name?):
integer int1 = integer(0, 100);
versus your definition of implicit which would be:
integer int1(1, 100);
In this case the first "explicit" call really doesn't have any advantage over the second "implicit" call. But there is still a difference. The first one actually creates a temporary using the two-argument constructor, which is then used to create int1 using the copy constructor. Although in practice the compiler will usually optimize away this additional copy, it still won't work if your copy constructor is private, whereas the second one only needs the two-argument constructor (you could even see this as disadvantage).
But now to the actual standard definitions of explicit and implicit. An explicit constructor call is any constructor call you, well, explicitly call. Practically speaking, whenever you use the parenthesis syntax () to create an object you explicitly call a constructor, otherwise it's an implicit constructor call (so to say, being done behind the scenes by the compiler):
integer int1; // implicit default constructor
integer int1(1, 100); // explicit two-arg constructor
integer int1 = integer(0, 100); // explicit two-arg constructor, implicit copy constructor
void func(integer); // function taking by-value
func(int1); // implicit copy constructor
So the only constructors that can be called implicitly are the default construtor and any one-argument constructors (including copy and move constructors). A special problem in this regard are one-argument constructors not being copy/move constructors:
struct integer
{
integer(int);
};
This allows the compiler to imlicitly call the the constructor to convert types, thus any int is implicitly convertible to integer:
void func(integer);
func(42); // implicit call to int-constructor
To disallow such behaviour you would have to mark the constructor explicit:
struct integer
{
explicit integer(int);
};
Which only allows it to be called explicitly (e.g. func(integer(42))) (but I guess you already knew this). This has the advantage that it doesn't introduce unnoticed/unwanted conversions behind the scenes, which can lead to all kinds of hard to find problems and ambiguities regarding overload resolution. It is therefore usual practice to mark any conversion constructors (one-argument non-copy/move constructors) explicit, and most probably also the reason why C++11 finally introduced explicit conversion operators.
So to sum up, according to your definition and example, there is really no advantage in using integer int1 = integer(1, 100); instead of integer int1(1, 100);, though it makes a (usually irrelevant) difference.
But according to the standard definitions, explicit constructor calls have plenty advantages over implicit ones, since the only way to actually construct an object explicitly is to use a, well, explicit constructor call, whereas implicit constructor calls are only done behind the scenes in certain situations and only work for zero- and one-argument constructors (as aschepler already pointed out). And explicitly marking conversion constructors as explicit has the advantage of disallowing unwanted implicit conversions behind the scenes.
Calling constructors explicitly allow you to construct object with arguments, rather than using the default constructor.
class Foo
{
public:
Foo() {}
Foo(int bar) : mBar(bar) {}
private:
int mBar;
}
Foo f; // Implicitly constructed with default constructor.
Foo f(7); // Explicitly constructed with argument for 'bar'
There are three ways a constructor can be called:
Implicitly, by declaring an instance of the type without initializing it
Also implicitly, by either initializing an instance with = or by causing an implicit conversion from the argument type to your class.
Explicitly calling the constructor, passing arguments.
Which of these you can use in a particular context depends on the constructors you're calling.
class Foo
{
Foo(); // 1
Foo(int a); // 2
explicit foo(const std::string& f); // 3
Foo(int c, int d); // 4
};
This constructor will be called implicitly when declaring Foo f;. Never attempt to call a constructor without arguments explicitly, as Foo f(); will declare a function!
This one can be called by writing Foo f = 42; or Foo f(42).
The explicit keyword forbids implicit conversion by writing Foo f = std::string("abc"); or function_taking_foo(function_returning_string());.
As there are multiple arguments, the explicit version is the only suitable.
I hate to say this, because it is so perverse, but there is an additional way to explicitly call the constructor.
class integer
{
int m ,n;
public:
integer (int x , int y);
};
integer :: integer (int x , int y )
{
m=x; n = y;
}
The constructor can be explicitly called on an already-constructed object.
integer i(1,100);
i.~integer();
i.integer::integer(2,200);
Here I've constructed (explicitly) an instance of integer. Then I've explicitly called its destructor. Then I've explicitly called the constructor again. I suppose you might use this idiom in testing. I am not aware of any place in the standard that forbids it. It works in Visual Studio 2010. I haven't tested a really wide range of compilers.
These calls are explicit for large values of 'explicit'.
If you make a function that takes a reference to a object of your class, and you pass it another type other than your object the constructor of your class will convert that type to an object of your class. Any one argument constructor is treated as a conversion constructor. If you declare that constructor explicit, then passing a different type other than your object to that function will not convert it and the compiler will return an error

Implicit VS Explicit Conversion

The C++ Standard Library by Nicolai M. Josuttis states:
There is a minor difference between
X x;
Y y(x) //explicit conversion
and
X x;
Y y = x; //implicit conversion
Following to say: "The former creates a new object of type Y by using an explicit conversion from type X, whereas the latter creates a new object of type Y by using an implicit conversion."
I'm a little confused about the concepts of explicit vs implicit conversion I guess. In both cases you're taking an X and pushing it into a Y per se - one uses a Y's constructor and one uses the assignment operator though.
What's the difference in how the conversion is treated in these two cases, what makes it explicit/implicit, and how does this tie into making a class constructor defined with the "explicit" key word, if at all?
one uses a Y's constructor and one uses the assignment operator though.
Nope. In the second case it's not an assignment, it's an initialization, the assignment operator (operator=) is never called; instead, a non-explicit one-parameter constructor (that accepts the type X as a parameter) is called.
The difference between initialization and assignment is important: in the first case, a new object is being created, and it starts its life with the value that it is being initialized with (hence why a constructor is called), while assignment happens when an object is assigned (~copied) to an object that already exists and already is in a definite state.
Anyway, the two forms of initialization that you wrote differ in the fact that in the first case you are explicitly calling a constructor, and thus any constructor is acceptable; in the second case, you're calling a constructor implicitly, since you're not using the "classical" constructor syntax, but the initialization syntax.
In this case, only one-parameter constructors not marked with explicit are acceptable. Such constructors are called by some people "converting" constructors, because they are involved in implicit conversions.
As specified in this other answer, any constructor not marked as explicit can take part in an implicit conversion for e.g. converting an object passed to a function to the type expected by such function. Actually, you may say that it's what happens in your second example: you want to initialize (=create with a value copied from elsewhere) y with x, but x first has to be converted to type Y, which is done with the implicit constructor.
This kind of implicit conversion is often desirable: think for example to a string class that has a converting (i.e. non-explicit) constructor from a const char *: any function that receives a string parameter can also be called with a "normal" C-string: because of the converting constructor the caller will use C-strings, the callee will receive its string object.
Still, in some cases one-parameters constructors may not be appropriate for conversion: usually this happens when their only parameter is not conceptually "converted" to the type of the object being created, but it is just a parameter for the construction; think for example about a file stream object: probably it will have a constructor that accepts the name of the file to open, but it makes no sense to say that such string is "converted" to a stream that works on that file.
You can also find some more complex scenarios where these implicit conversions can completely mess-up the behavior that the programmer expects from overload resolution; examples of this can be found in the answers below the one I linked above.
More simply, it can also happen that some constructors may be very heavyweight, so the class designer may want to make sure that they are invoked explicitly. In these cases, the constructor is marked as explicit, so it can be used only when called "explicitly as a constructor" and doesn't take part in implicit conversions.
one uses the assignment operator though
No, it does not. It calls the constructor directly.
The reason why one is explicit and one is implicit is because implicit conversions can happen when you don't want them to. Explicit ones cannot. The easiest example of this is bool.
Let's say that you invent some type which can be either true or false- like a pointer. Then let's further say that you decide that in order to make life easier for your users, you let it convert to bool implicitly. This is great- right up until the point where one of your users does something dumb.
int i = 0;
i = i >> MyUDT();
Oh wait- why does that even compile? You can't shift a MyUDT at all! It compiles because bool is an integral type. The compiler implicitly converted it to a bool, and then to something that can be shifted. The above code is blatantly dumb- we only want people to be able to convert to a bool, not a bool and anything else that a bool might want to do.
This is why explicit conversion operators were added to C++0x.
The first form is direct initialization. The second is copy initialization.
Copy initialization implicitly calls a converting constructor or conversion operator and then explicitly calls a copy constructor (the copy constructor call may be elided, but an accessibility check must still be performed).
Consider a third possibility, which is copy-initialization, but the conversion is explicit:
Y y = Y(x);
or
Y y = (Y)x;
The Implicit casting doesn't require any casting operator. This casting is normally used when converting data from smaller integral types to larger or derived types to the base type.
int iVal = 100;
double dVal = iVal;
The explicit converting constructor is preferred to the implicit conversion operator because in the latter case there is an additional call to the copy constructor.Implicit and Explicit converstions