I would like to know where is this form of constructor calling is documented.
This syntax apparently works since Visual Studio version 6.0 (I know it does not compile using G++).
Please note that I am not looking for alternatives and I don't need to know that it's good or evil.
class Foo
{
public:
int m_value;
Foo() : m_value(0) {}
};
Foo o;
o.m_value = 5;
o.Foo::Foo(); // Explicit constructor call!
EXPECT_EQ(0, o.m_value); // True!
I first found this syntax reading this article:
http://www.dreamincode.net/forums/topic/160032-finite-state-machines/
This post also refers to this syntax as well:
Can I call a constructor from another constructor (do constructor chaining) in C++?
Another post discussing the matter:
Explicit constructor call in C++
The supposed explicit constructor call is not valid C++ syntax. The fact that MSVC accepts such code is a bug.
Its of no use since you are creating a transient object in between and it dies when the scope ends.What ever value contain in object o remains the same, so u got the True value
Related
I am trying to understand the following code that I saw today. I already tried to find a related question, but since I have no idea what this feature of C++ is called it is hard to find related posts. A hint on the correct search term might already help me.
struct A
{ int x; };
struct B
{ B(A a) {}; };
int main()
{
B b{ { 5 } }; // works, seems to create a struct A from {5} and pass it to B's constructor
std::make_unique<B>({ 5 }); // doesn't compile
return 0;
}
Why is {5} not used to create a struct A when passed to make_unique but is used this way in the constructor of B?
If B had a second constructor B(int foo) {}; this one would be used instead of the one frome above (at least that is what I found by trial and error). What is the rule to decide if the argument is automatically used to create a struct A or if it is used directly as int in the constructor?
I am using Visual C++ 14.0
Here's a simplified demonstration:
struct X { X(int); };
void foo(X );
template <typename T> void bar(T );
foo({0}); // ok
bar({0}); // error
The issue is that braced-init-lists, those constructs that are just floating {...}s, are strange beasts in C++. They don't have a type - what they mean must be inferred from how they're actually used. When we call foo({0}), the braced-init-list is used to construct an X because that's the argument - it behaves as if we wrote X{0}.
But in bar({0}), we don't have sufficient context to know what to do with that. We need to deduce T from the argument, but the argument doesn't have a type - so what type could we possibly deduce?
The way to make it work, in this context, is to explicitly provide that T:
bar<X>({0}); // ok
or provide an argument that has a type that can be deduced:
bar(X{0}); // ok
In your original example, you can provide the A directly:
make_unique<B>(A{5})
or the B directly:
make_unique<B>(B({5}))
or just use new:
unique_ptr<B>(new B({5}))
or, less preferred and somewhat questionable, explicitly specify the template parameter:
make_unique<B, A>({5});
A constructor with a single non-default parameter (until C++11) that is declared without the function specifier explicit is called a converting constructor. Your A and B are instances of such constructors (this explains, why your first call works fine.) The problem is, that std::make_unique impedes these explicit calls. Anyhow, it might be a good idea, to not trust in these automatic creation in the first place and spent a few chars to show types. This could improve the readability of the code.
I just extracted the following problem in our project. The following code just compiles fine with g++
#include <vector>
class A {};
typedef std::vector<A*> vec_t;
class bar {
public:
bar(vec_t) {};
};
class foo
{
public:
foo(bar* a = new bar(vec_t())) {};
};
class B
{};
int main()
{
return 0;
}
However, the Visual Studio Compiler (VC12, but I presume all others too) doesn't understand that in the default argument for the c'tor of foo the c'tor of bar is called which takes an instance of a vector as an argument. This causes an error for every class/struct declared after this expression:
error C2462: 'B' : cannot define a type in a 'new-expression'
I don't want to discuss the software design of the c'tor, but is this a compiler issue or just not allowed in standard C++ and the g++ just not being strict about that?
First, I thought that a template-instantiation in a default parameter may be not allowed or nested c'tors in a default argument. However, if I use another c'tor of the vector:
foo(bar* a = new bar(vec_t(0))) {}
it compiles with MSVC. I just can't see why the upper version shouldn't compile? Any thoughts on that?
It looks like this is an issue with the "most vexing parse" (see the Wikipedia article on it for more info). One way to disambiguate the new expression is to add parentheses around the constructor like this
foo(bar* a = new bar((vec_t()))) {};
When it comes to standards compliance I'm not sure. I skimmed section 6.8 (Ambiguity Resolution) and 5.3.4 (New) of N3690 and without thinking about it too hard nothing stood out either way. Maybe a real language lawyer will need to step in to give an answer.
When I compile and run this with Visual C++ 2010:
#include <iostream>
int main() {
int subtrahend = 5;
struct Subtractor {
int &subtrahend;
int operator()(int minuend) { return minuend - subtrahend; }
} subtractor5 = { subtrahend };
std::cout << subtractor5(47);
}
I get the correct answer, 42.
Nevertheless, the compiler complains that this is impossible:
Temp.cpp(9) : warning C4510: main::Subtractor : default constructor could not be generated
Temp.cpp(6) : see declaration of main::Subtractor
Temp.cpp(9) : warning C4512: main::Subtractor : assignment operator could not be generated
Temp.cpp(6) : see declaration of main::Subtractor
Temp.cpp(9) : warning C4610: struct main::Subtractor can never be instantiated - user defined constructor required
What's going on?
The first two warnings are just letting you know that the implicitly declared member functions cannot be generated due to the presence of a reference data member.
The third warning is a Visual C++ compiler bug.
All three warnings can be ignored with no ill effects, though you can easily make all three go away by making the reference data member a pointer instead (reference data members are almost never worth the trouble).
The first warning is to tell you that a reference value cannot be defaultly constructed(references are guaranteed to point to some value). Switch the subtrahend to a regular integer and the problem will go away.
I am pretty sure the second warning is of similar nature.
(Just saying, it is generally much better to rely on something like boost::function or a similar implementation(std::tr1::function?) instead of writing this code manually)
It's because the variable subtractor5 is an unnamed struct. If you want to make the errors go away, give the structure used for subtractor5 a name.
For example:
struct subtractor {
:
} subtractor5 = { subtrahend };
I unfortunately don't know enough C++ language-ese to know why it works, but I do know why the warning happens.
A user defined constructor is mandatory in following cases:
Initializing constant data members (const int c_member;).
Initializing reference data members (int & r_member;)
Having a data member whose type doesn't have default constructor. Eg:
class NoDefCtor
{
public:
NoDefCtor(int);
};
class ContainThat
{
NoDefCtor no_ctor_member;
};
Inheriting from a base class, where base class doesn't have default constructor. Almost same as above (NoDefCtor).
I'm seeing some different behavior between g++ and msvc around value initializing non-copyable objects. Consider a class that is non-copyable:
class noncopyable_base
{
public:
noncopyable_base() {}
private:
noncopyable_base(const noncopyable_base &);
noncopyable_base &operator=(const noncopyable_base &);
};
class noncopyable : private noncopyable_base
{
public:
noncopyable() : x_(0) {}
noncopyable(int x) : x_(x) {}
private:
int x_;
};
and a template that uses value initialization so that the value will get a known value even when the type is POD:
template <class T>
void doit()
{
T t = T();
...
}
and trying to use those together:
doit<noncopyable>();
This works fine on msvc as of VC++ 9.0 but fails on every version of g++ I tested this with (including version 4.5.0) because the copy constructor is private.
Two questions:
Which behavior is standards compliant?
Any suggestion of how to work around this in gcc (and to be clear, changing that to T t; is not an acceptable solution as this breaks POD types).
P.S. I see the same problem with boost::noncopyable.
The behavior you're seeing in MSVC is an extension, though it's documented as such in a roundabout way on the following page (emphasis mine) http://msdn.microsoft.com/en-us/library/0yw5843c.aspx:
The equal-sign initialization syntax is different from the function-style syntax, even though the generated code is identical in most cases. The difference is that when the equal-sign syntax is used, the compiler has to behave as if the following sequence of events were taking place:
Creating a temporary object of the same type as the object being initialized.
Copying the temporary object to the object.
The constructor must be accessible before the compiler can perform these steps. Even though the compiler can eliminate the temporary creation and copy steps in most cases, an inaccessible copy constructor causes equal-sign initialization to fail (under /Za, /Ze (Disable Language Extensions)).
See Ben Voigt's answer for a workaround which is a simplified version of boost::value_initialized, as pointed out by litb in a comment to Ben's answer. The docs for boost::value_initalized has a great discussion of the problem, the workaround, and some of the pitfalls of various compiler issues.
I don't think template metaprogamming is needed. Try
template <class T>
void doit()
{
struct initer { T t; initer() : t() {} } inited;
T& t = inited.t;
...
}
There's §12.8/14:
A program is ill-formed if the copy constructor or the copy assignment operator for an object is implicitly used and the special member function is not accessible.
And then there's §12.8/15:
When certain criteria are met, an implementation is allowed to omit the copy construction of a class object, even if the copy constructor and/or destructor for the object have side effects.
So, the question is really, if the implementation omits the call to the copy constructor (which it is clearly allowed to do), is the copy constructor actually used?
And, the answer to that is yes, per §3.2/2:
A copy constructor is used even if the call is actually elided by the implementation.
Have you seen what happens when you compile using /Wall with MSVC? It states the following about your class:
nocopy.cc(21) : warning C4625: 'noncopyable' : copy constructor could not be
generated because a base class copy constructor is inaccessible
nocopy.cc(21) : warning C4626: 'noncopyable' : assignment operator could not be
generated because a base class assignment operator is inaccessible
GCC remedy:
create a copy constructor for noncopyable (and an assignment operator ideally!) that does what it can to copy the information from noncopyable_base, namely invoking the constructor for noncopyable_base that has no parameters (since that is the only one accessible by noncopyable) and then copying any data from noncopyable_base. Given the definition of noncopyable_base, however, it seems there is no data to copy, so the simple addition of noncopyable_base() to the initializer list of a new noncopyable(const noncopyable &) function should work.
Take note of what MSVC said about your program though. Also note that if you use T t() rather than T t = T(), another warning (C4930) is generated by MSVC, though GCC happily accepts it either way without any warning issued.
Observation: the codes pasted below were tested only with GCC 4.4.1, and I'm only interested in them working with GCC.
Hello,
It wasn't for just a few times that I stumbled into an object construction statement that I didn't understand, and it was only today that I noticed what ambiguity was being introduced by it. I'll explain how to reproduce it and would like to know if there's a way to fix it (C++0x allowed). Here it goes.
Suppose there is a class whose constructor takes only one argument, and this one argument's type is another class with a default constructor. E.g.:
struct ArgType {};
class Class
{
public:
Class(ArgType arg);
};
If I try to construct an object of type Class on the stack, I get an ambiguity:
Class c(ArgType()); // is this an object construction or a forward declaration
// of a function "c" returning `Class` and taking a pointer
// to a function returning `ArgType` and taking no arguments
// as argument? (oh yeh, loli haets awkward syntax in teh
// saucecode)
I say it's an object construction, but the compiler insists it's a forward declaration inside the function body. For you who still doesn't get it, here is a fully working example:
#include <iostream>
struct ArgType {};
struct Class {};
ArgType func()
{
std::cout << "func()\n";
return ArgType();
}
int main()
{
Class c(ArgType());
c(func); // prints "func()\n"
}
Class c(ArgType funcPtr()) // Class c(ArgType (*funcPtr)()) also works
{
funcPtr();
return Class();
}
So well, enough examples. Anyone can help me get around this without making anything too anti-idiomatic (I'm a library developer, and people like idiomatic libraries)?
-- edit
Never mind. This is a dupe of Most vexing parse: why doesn't A a(()); work?.
Thanks, sbi.
This is known as "C++'s most vexing parse". See here and here.
Let's simplify a little.
int f1();
What's that? The compiler (and I) say it's a forward declaration for a function returning an integer.
How about this?
int f2(double );
The compiler (and I) say it's a forward declaration for a function taking a double argument and returning an int.
So have you tried this:
ClassType c = ClassType(ArgType());
Check out the c++ faq lite on constructors for explanations and examples
Based on the "C++0x allowed", the right answer is (probably) to change the definition to:
Class c(ArgType {});
Simple, straightforward and puts the burden entirely on the user of the library, not the author!
Edit: Yes, the ctor is invoked -- C++ 0x adds List-Initialization as an unambiguous way to delimit initializer lists. It can't be mis-parsed like in your sample, but otherwise the meaning is roughly the same as if you used parentheses. See N3000, the third bullet point under §8.5.4/3. You can write a ctor to receive an initializer list as a single argument, or the items in the initializer list can be matched up with the ctor arguments individually.