#include <initializer_list>
#include <iostream>
using namespace std;
struct Y {};
struct X
{
X(initializer_list<Y>) { cout << "yay" << endl; }
explicit X() { cout << "boo" << endl; }
};
X f()
{
return {};
}
int main()
{
f();
return 0;
}
This prints out "boo". Why doesn't it print out "yay" ?
Is there anyway to differentiate the following two constructions:
X()
X{}
or
return X();
return {};
or
void g(const X&)
g(X())
g({})
Thanks.
Is there anyway to differentiate the following two constructions:
No. They are not different constructs.
The primary purpose of the {} constructor syntax was to introduce uniform initialization, to have initialization work the same everywhere. If there was a difference between them, it wouldn't be uniform.
If you want to use the empty initializer list constructor, you have to state that you're passing an initializer list explicitly. Like this: return initializer_list<Y>{}; Of course, one of the other purposes of uniform initialization is to not have to type out typenames so much, so you can achieve the same effect with return {{}};
return {}; will always use a default constructor if there is one.
return X({}); or return {{}}; will construct from an empty initialiser list.
It uses the default constructor because list initialization with {} is meant to be a short form of value initialization always, disregarding of other constructors, even if they are initializer list constructors.
Is there anyway to differentiate the following two constructions: ...
The X() is always value initialization, while X{} is only value initialization if X has a default constructor. If it is an aggregate, then X{} is aggregate initialization (initializing the members of X by a {} recursively). If it only has initializer list constructors and no default constructors, then X() is invalid and X{} could be valid
struct A { A(initializer_list<int>); };
A a = A{}; // valid
A b = A(); // invalid
Essentially, what X{} does depends on what X is. But X() always value initializes.
... or return X(); vs return {};
Something subtle to mention... In return {} the target is copy-list-initialized, while in return X(); first direct-initializes an X. But even though it is copy-list-initialized, it can use an explicit default constructor, because value initialization doesn't care about explicit. However when you do return {} and you try to use an explicit non-default constructor you will error out
struct A {
explicit A(initializer_list<int>);
};
A f() { return {}; } // error!
struct B {
explicit B();
};
B g() { return {}; } // OK
You could be a bit more explicit:
return initializer_list<Y>();
Related
I wrote some code S s; ... s = {};, expecting it to end up the same as S s = {};. However it didn't. The following example reproduces the problem:
#include <iostream>
struct S
{
S(): a(5) { }
S(int t): a(t) {}
S &operator=(int t) { a = t; return *this; }
S &operator=(S const &t) = default;
int a;
};
int main()
{
S s = {};
S t;
t = {};
std::cout << s.a << '\n';
std::cout << t.a << '\n';
}
The output is:
5
0
My questions are:
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
Is there a tidy workaround, without changing S?
My intent is s = S{}; . Writing s = {}; would be convenient if it worked. I'm currently using s = decltype(s){}; however I'd prefer to avoid repeating the type or the variable name.
Why is operator=(int) selected here, instead of "ambiguous" or the other one?
{} to int is the identity conversion ([over.ics.list]/9). {} to S is a user-defined conversion ([over.ics.list]/6) (technically, it's {} to const S&, and goes through [over.ics.list]/8 and [over.ics.ref] first before coming back to [over.ics.list]/6).
The first wins.
Is there a tidy workaround?
A variation of the trick std::experimental::optional pulls to make t = {} always make t empty.
The key is to make operator=(int) a template. If you want to accept int and only int, then it becomes
template<class Int, std::enable_if_t<std::is_same<Int, int>{}, int> = 0>
S& operator=(Int t) { a = t; return *this; }
Different constraints can be used if you want to enable conversions (you'd probably also want to take the argument by reference in that case).
The point is that by making the right operand's type a template parameter, you block t = {} from using this overload - because {} is a non-deduced context.
...without changing S?
Does template<class T> T default_constructed_instance_of(const T&) { return {}; } and then s = default_constructed_instance_of(s);count?
First of all, the case has nothing to do with the "int" version of the assignment operator, you can just delete it. You can actually delete the other assignment operator too as it will be generated by the compiler. IE this kind of type automatically receives copy/move constructors and the assignment operator. (ie they are not prohibited and you are just repeating what the compiler does automatically with explicit notation)
The first case
uses copy initialization:
S s = {}; // the default constructor is invoked
That is a post-construction copy assignment, yet compilers optimize such simple cases. You should use direction initialization instead:
S s{}; // the default constructor is invoked (as you have it)
Note, you can also write:
S s; // the default constructor is invoked if you have it
The second case
What you should write is direct initialization of the right hand side of the copy assignment:
t = S{};
This notation will invoke the default constructor (if there is one), or value initialization for the members (as long as the type is an aggregate). Here is the relevant info: http://en.cppreference.com/w/cpp/language/value_initialization
I'm recently learning about move constructor, and I met a strange problem.
I have the following code:
#include <iostream>
class a
{
public:
a() { printf("default\n"); }
a(const a& aa) { printf("const lr\n"); }
a(a& aa) { printf("lr\n"); }
a(a&& aa) { printf("rr\n"); }
a(const a&& aa) { printf("const rr\n"); }
};
a foo()
{
return a();
}
void func(a& a) {
printf("func lr\n");
}
void func(a&& aa) {
printf("func rr\n");
}
int main()
{
printf("a1: ");a a1;
printf("a2: ");a a2(a1);
printf("a3: ");a a3(std::move(a2));
printf("a4: ");a a4(foo());
printf("a5: ");a a5(std::move(foo()));
func(foo());
}
The output is:
a1: default
a2: lr
a3: rr
a4: default
a5: default
rr
default
func rr
All is good except for a4. I expect that the return type of foo() is a rvalue. I think the call of func() at last has proved that. So why doesn't the move constructor called when constructing a4? And at the same time, it is called when constructing a5.
That's probably because of copy_elision.
Under the following circumstances, the compilers are required to omit
the copy- and move- construction of class object:
In initialization, if the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object:
T x = T(T(T())); // only one call to default constructor of T, to initialize x
In a function call, if the operand of a return statement is a prvalue and the return type of the function is the same as the type of that prvalue:
T f() { return T{}; }
T x = f(); // only one call to default constructor of T, to initialize x
T* p = new T(f()); // only one call to default constructor of T, to initialize *p
Your situation falls under the second case.
If we have a non-movable, non-copyable class with non-explicit constructor, we can return it and use as follows (in C++11):
#include <iostream>
class NonCop
{
public:
/*non explicit*/ NonCop(int a, int b) : number(a + b) {}
NonCop(const NonCop&) = delete;
int number;
};
NonCop get_non_cop()
{
return {1, 2};
}
int main()
{
NonCop &&nc = get_non_cop();
std::cout << "three: " << nc.number << std::endl;
return 0;
}
However if the constructor is explicit, it doesn't work. Is there any method of doing this in C++11/C++14 with no modifications in NonCop?
Currently I'm using workaround with deriving from NonCop with wrapper that "deexplicits" the constructor but it doesn't seem very pretty.
No, this isn't possible. There is no mechanism to call explicit constructors while returning from a function in C++11 or 14 without having an implicit move or copy (that the compiler will certainly elide).
In C++17 you can just type return NonCop(1,2); and due to "guaranteed elision" it will no longer require a move or copy constructor.
But this is C++, so yes, I can make your code work with zero additional overhead. By cheating, and returning a different type.
template<class T>
struct implicit_construct:T {
template<class...Ts>
implicit_construct(Ts&&...ts):
T(std::forward<Ts>(ts)...) // note: this is an EXPLICIT construction
{}
};
implicit_construct<NonCop> get_non_cop()
{
return {1, 2};
}
Live example.
An implicit_construct<NonCop> derives from a NonCop, so you can store the return value in a NonCop&&.
If you are writing NonCop yourself, then what I'd do is add:
struct explicit_construct_t {};
// ...
struct NonCop {
// ...
template<class...Ts>
NonCop( explicit_construct_t, Ts&&...ts ):
NonCop( std::forward<Ts>(ts)... )
{}
// ...
};
which means you can call explicit constructors by prefixing it with a explicit_construct_t to call them implicitly:
NonCop get_non_cop() {
return {explicit_construct_t{}, 1, 2};
}
Unfortunatelly, in this context you can't return the temporary object, since in a return by value expression the compiler requires that the object's copy constructor is accessible, even if this object is going to be copy elided in the end. However, you could return a std::unique_ptr instead of concrete object.
std::unique_ptr<NonCop> get_non_cop() {
return std::make_unique<NonCop>(1, 2);
}
Live Demo
I played around with explicit constructors and their behavior, so I created this class:
#include <iostream>
class X
{
public:
explicit X(void)
{
std::cout << "Default constructor\n";
}
explicit X(X const& x)
{
std::cout << "Copy constructor\n";
}
explicit X(X&& x)
{
std::cout << "Move constructor\n";
}
};
Which is basically just a stub to to test explicit constructors.
Then I wanted to try several situations. So I tried this:
X foo(void)
{
X a{};
return a; // ERROR: no matching constructor found!
}
int main()
{
X w{}; // Default Constructor
X x{w}; // Copy Constructor
X y{std::move(x)}; // Move Constructor
X z{foo()};
}
And as you can see I can't return a inside foo(). I know it tries to initialize the return type Foo with the copy constructor, but for some reason it can't use it.
How come it can't use my provided copy constructor? I know that the explicit specification causes the problem, because when I remove it from the copy constructor it works. But why?
What confuses me even more is that I can do the following:
void bar(const X& a) { /* */ }
bar(X{});
It doesn't complain. But shouldn't bar() construct it's parameter a the same way foo() constructs its return type?
When you are returning from foo:
X foo()
{
X a{};
return a;
}
You are implicitly copying a into the return of foo. But the copy constructor is marked explicit, so that is disallowed.
I'm not sure there is ever a reason to mark the copy/move constructors explicit.
I think you've misunderstood the meaning of explicit. An explicit constructor WILL NOT BE USED FOR IMPLICIT TYPE CONVERSIONS/CASTS. This means the
X foo(void){
X a{};
return a; // ERROR: no matching constructor found!
}
won't compile since you've already told the compiler not to use the copy constructor implicitly.
I reckon that what you want to achieve is "move" rather than copy a. As long as there is a (normal) move constructor in your class, a will be moved rather than copied anyway - this is the default behaviour. Actually, even with c++99, most compilers are clever enough to optimise out this copy anyway.
You can't because you said you didn't want the compiler to use it implicitly when you declared it explicit.
explicit X(X const& x)
But x has to be copied into the return value. Just change it to
X(X const& x)
and everything will work.
Live on Coliru
I know that default constructors initialize objects to their default values, but how do we view these values? If there's a variable of type int, it is supposed to be initialized to 0. But how do we actually view these default values of the constructors? Can anyone please provide a code snippet to demonstrate the same?
Unless specified otherwise, objects are constructed with their default constructor, only if one is available.
And for example ints are not initialized.
This is a common source of huge troubles and bugs, because it can have any value.
So the rule is , always initialise your variables, and for a class you do it in the initialization list
class A
{
private:
int i;
float f;
char * pC;
MyObjectType myObject;
public:
A() : // the initialisation list is after the :
i(0),
f(2.5),
pC(NULL),
myObject("parameter_for_special_constructor")
{}
}
}
In C++, int is not a class and does not have a default (or any other) constructor.
An int is not guaranteed to be initialised to 0.
If you have a class that has an int as an attribute, you should explicitly initialise it in each of the class's constructors (not just the default one).
class sample
{
private:
int x;
public:
sample()
:x(0)
{
}
sample(const int n)
:x(n)
{
}
sample(const sample& other)
:x(other.x)
{
}
// [...]
};
This way you (and users of your class) can "view" the default values.
Good coding practice: write your own constructor, so you know how it will be initialized. This is portable and guaranteed to always have the same behaviour. Your code will be easier to read and the compiler knows how to make that efficient, especially when using the special notation:
class Foo
{
public:
Foo() : i(0), j(0) {}
private:
int i;
int j;
};
AFAIK, if T is a type (not necessarily a class), T() returns a default value for the type T. Here's a small test I ran:
int main()
{
char c = char();
int i = int();
cout << "c = " << hex << (int) c << endl;
cout << "i = " << i << endl;
}
The output is:
c = 0
i = 0
Default constructors do not automatically initialise ints to 0. You can use parentheses to indicate the default value though.
struct X
{
int x;
};
struct X x1; // x1.x is not necessarily 0
struct Y
{
int y;
Y() : y()
{
}
};
struct Y y1; // y1.y will be 0
show your code
And if your int value is a member of class .
you must give it a value in your default constructor func
The default constructor is which can be invoked with 0 parameters. For example
struct X
{
X(int x = 3) //default constructor
{
//...
}
};
It initializes the object to whichever state you code it to initialize. However, if you don't define any constructor at all the compiler will attempt to generate a default constructor for you - which, in turn is equivalent to a constructor with no arguments and no body. That means that all the members of class/struct type will be initialized with their def. ctors and all the members of primitive types like int will remain uninitialized. Please note that I specialy noted that the compiler will attempt to generate a dflt ctor, because it can fail to do so, for example when one or more members of the class do not have default constructors. HTH
AS soon as you have created an object start printing the values such as ob.x.
Thats the only way u can know what default constructor has assigned to the variables.