class classname(value); & class classname=value; difference when constructor is explicit - c++

When constructor is explicit, it isn't used for implicit conversions. In the given snippet, constructor is marked as explicit. Then why in case foo obj1(10.25); it is working and in foo obj2=10.25; it isn't working ?
#include <iostream>
class foo
{
int x;
public:
explicit foo( int x ):x(x)
{}
};
int main()
{
foo obj(10.25); // Not an error. Why ?
foo obj2 = 10.25; // Error
getchar();
return 0;
}
error: error C2440: 'initializing' : cannot convert from 'double' to 'foo'

These two forms of initialization are technically different. The first (foo obj(10.25);) is called direct initialization. The second (foo obj = 10.25;) is called copy initialization.
explicit constructors can only be used when you explicitly initialize an object. Direct initialization is one form of explicitly initializing an object. The other form of explicit initialization is the use of a cast.

There is a difference between these two lines of code. The first line,
foo obj(10.25);
explicitly calls your foo constructor passing in 10.25. This syntax, in general, is a constructor call.
The second line,
foo obj2 = 10.25;
tries to implicitly convert from 10.25 to an object of type foo, which would require use of an implicit conversion constructor. In this example, you've marked the constructor explicit, there's no implicit conversion constructor available, and so the compiler generates an error.

Your "not an error" case is an explicit construction. The compiler is doing what you told it to do.

In the first case you are not implicitly converting 10.25 to foo. You are converting it to an int, so it's not an error. Saying foo obj(10.25) is regarded as a direct call to the constructor to initialize a foo object.
In the second case, you are trying to implicitly convert 10.25 to a foo. The constructor marked explicit will not be considered (as you rightfully say), and therefor you will get an error.

Related

initialise object with equal operator

In the class defined as below named foo
class foo{
private:
string str;
public:
foo operator = (string s){
str = s;
}
};
int main(){
foo a = "this initialization throwing an error";
foo b;
b = "but assignment after declaration is working fine";
}
error: conversion from 'const char [38]' to non-scalar type 'foo' requested
The above error is caused only when I am assigning value to the object instance with declaration but if I am assigning separately from declaration then the overloaded equal = operator is working fine.
I want in any method to assign an string to the object with equal operator
and as a declaration like foo a = "abcd";
When you have
type name = something;
You are not doing assignment but instead you have copy-initialization (do not that there can be a move even though it is called copy). This means that you need a constructor in your class whose parameter matches that of the thing on the right hand side of the =.
In this case you do not have a constructor that takes a std::string, const char* or const char[] so the compiler is unable to construct an instance there.
The reason the second case works is that
b = "but assignment after declaration is working fine";
Is not trying to construct anything and therefore it calls the assignment operator which does work because
"but assignment after declaration is working fine"
can be converted to a std::string.
If you want your class to be constructable from a string literal or cstring then you can add a constructor to it in the form of
foo(const char* str) : str(str) {}
What you have in the first case is called copy initialization and as stated in documentation:
The equals sign, =, in copy-initialization of a named variable is not
related to the assignment operator. Assignment operator overloads have
no effect on copy-initialization.
Hense the error. So possible solutions:
First you can create a constructor, that accepts std::string:
foo( const std::string &s );
that will allow you to create foo by this:
foo f( "abc" );
or even this:
foo f = foo( "abc" );
but your statement will still fail, because of:
in addition, the implicit conversion in copy-initialization must
produce T directly from the initializer, while, e.g.
direct-initialization expects an implicit conversion from the
initializer to an argument of T's constructor.
so to make your statement work as it is you need to add this ctor:
foo( const char *str );
Note: when you add proper ctor you do not need to define assignment operator - conversion constructor will be used. And your overloaded assignment operator should return reference to foo.
When you create an object, the code initializes it with a constructor, even when the creation uses an = sign:
struct S {
S(int);
};
S s = 3; // initialization, not assignment
Formally, that initialization uses S(int) to create a temporary object of type S, and then uses the copy constructor to construct the object s from the temporary object.
That's vastly different from assignment, which deals with an already existing object:
S s1;
s1 = 3; // assignment
Here, the assignment would use the assignment operator if S defined one. That's why the b = line in the original code works.
Your problem is that
foo a = "initialization string";
attempts to create an object of type foo however there is no constructor defined that accepts a parameter of type string.
You could define one like this:
foo(const std::string& s) : str(s) {}
foo(const char* s) : str(s) {}
For starters though the compiler does not issue a diagnostic message nevertheless the assignment operator in the class definition
class foo{
private:
string str;
public:
foo operator = (string s){
str = s;
}
};
is invalid because it returns nothing while it has return type foo.
You should it write like
foo & operator = ( const std::string &s){
str = s;
return *this;
}
As you declared neither the default constructor nor the copy constructor then the compiler implicitly declared them instead of you.
So in fact your class has only two constructor. The default constructor that has the following declaration
foo();
and the copy constructor that has the following declaration
for( const foo & );
In this statement
foo a = "this initialization throwing an error";
the compiler assumes that in the right side there is an object of type foo and you are going to use it to create the object a. That is in this declaration the compiler tries to apply the implicitly created copy constructor. To so so it need to convert the string literal to an object of type foo. However the class does not have a conversion constructor that is a constructor with a parameter that can accept the string literal. As result the compiler issues the error
error: conversion from 'const char [38]' to non-scalar type 'foo'
requested
const char[33] is the type of the string literal in the right side of the declaration.
In this code snippet
foo b;
b = "but assignment after declaration is working fine";
at first there is created the object b of the type foo using the implicitly defined by the compiler default constructor and then in the second statement there is used the assignment operator that is explicitly defined in the class. As it follows from the definition of the operator it assigns data member str with a temporary object of type std::string that is constructed from the used string literal. It is possible because the class std::string has a corresponding conversion constructor.

Not getting the expected behavior with "explicit" keyword in c++

I have the following classes
class abc
{
private:
string name_;
public:
explicit abc(string name);
};
class xyz
{
private:
abc obj_abc_;
public:
xyz ():obj_abc_("NOTHING") { }; //I think this should give an error since explicit is used.
};
According to what i have understood about explicit, i should be getting a compiler error whenever xyz constructor is being called; because i am initializing the obj_abc by simply assigning it to a string. But i am not getting any compiler error here.
What am i missing?
explicit on a constructor means that the constructor can't be used for conversion from its parameter type to the class type. So an implicit conversion
abc x = "NOTHING";
will be forbidden if the constructor is explicit, but not otherwise. An explicit conversion
abc x("NOTHING");
will be allowed in either case. In your case, direct initialisation in an initialiser list is explicit; so your explicit constructor can be used for that.
explicit doesn't prevent implicit conversions to the constructor parameter's type; so the conversion from "NOTHING" to string in your example is allowed in either case, using the non-explicit string constructor.
Besides the syntax error (use { } instead of ;) you aren't assigning or implicitly converting anything. You're explicitly constructing the object in the initialisation list.

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

Explicit Assignment vs Implicit Assignment

I'm reading a tutorial for C++ but it didn't actually give me a difference (besides syntax) between the two. Here is a quote from the tutorial.
You can also assign values to your variables upon declaration. When we
assign values to a variable using the assignment operator (equals
sign), it’s called an explicit assignment:
int nValue = 5; // explicit assignment
You can also assign values to variables using an implicit assignment:
int nValue(5); // implicit assignment
Even though implicit assignments look a lot like function calls, the
compiler keeps track of which names are variables and which are
functions so that they can be resolved properly.
Is there a difference? Is one more preferred over the other?
The first is preferred with primitive types like int; the second with types that have a constructor, because it makes the constructor call explicit.
E.g., if you've defined a class Foo that can be constructed from a single int, then
Foo x(5);
is preferred over
Foo x = 5;
(You need the former syntax anyway when more than one argument is passed, unless you use Foo x = Foo(5, "hello"); which is plain ugly and looks like operator= is being called.)
For primitive types both are equivalent, it is for user defined class types that there is a difference. In both cases the code that gets executed will be the same (after basic optimizations are performed), but the requirements on the types differ if the element from which we are initializing is not of the type that we are constructing.
The copy-initialization (T t = u;) is equivalent to copy construction from a temporary of type T that has been implicitly converted from u to t. On the other hand direct-initialization is equivalent to a direct call to the appropriate constructor.
While in most circumstances there will be no difference, if the constructor that takes the u is declared explicit or if the copy-constructor is inaccessible, then copy-initialization will fail:
struct A {
explicit A( int ) {}
};
struct B {
B( int ) {}
private:
B( B const & );
};
int main() {
A a(1); // ok
B b(1); // ok
// A a2 = 1; // error: cannot convert from int to A
// B b2 = 1; // error: B( B const & ) is not accessible
}
For some historical background, initially primitive types had to be initialized with copy-initialization. When *initializer-list*s were added to the language to initialize member attributes from a class, it was decided that primitive types should be initialized with the same syntax that classes to keep the syntax in the initializer list uniform and simple. At the same time allowing the initialization of classes by means of copy-initialization makes user defined types closer to primitive types. The differences in the two initialization formats comes naturally: int a = 5.0; is processed as a conversion from 5.0 to int, and then initialization of a from the int. The same goes with user defined types: T u = v; is processed as conversion from v to T, and then copy construction of u from that converted value.
when you are declaring a variable and initializing it, they are functionally the same in that context. I usually refer to the two as:
int nValue = 5; // assignment syntax
and
int nValue(5); // construction syntax
For basic types, I prefer assignment over construction since it is more natural, especially for those who have programmed in other languages.
For class types, I prefer construction syntax since it obviates the existence of a constructor function.