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.
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.
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
C++11 introduced this:
struct MyClass {
int foo = 0; //*
};
Until now I've been using this without thinking about it, but now I'm wondering:
Is this initialization doing/executing any actual initialization at this particular line (//* in the code), or is this a mere convenience notation that only does/executes something later, when the object is actually constructed?
Not sure what you mean by "later" and "at this particular line", but the above is equivalent to the following:
struct MyClass {
MyClass() : foo(0) { }
};
So if I understand your question correctly, then the answer is: "Yes, only when the object is actually constructed".
Declarations are not executable code, they do not execute anything. This is merely a convenient notation for inserting initialization of foo to zero into every constructor that you define (or into an implicitly defined default constructor, if you do not define any constructors yourself).
I would like to know, when someone gives you a template for a default constructor in C++ and in the parameter there is a series of unnamed variables that somehow are assigned values. What does this mean?
Is this legal?
How can one access these variables?
Example I received:
IntSet::IntSet(int = -1, int = -1, int = -1, int = -1); //default constructor
I would appreciate any answers that clarify this use!
It's perfectly legal to not name the arguments in the declaration or in the definition of a function. It's also perfectly legal to use different names for a given argument in the declaration and definition.
Note that if a parameter that is not named in the definition is not accessible. Why do this? A lot of compilers can be made to complain about unused arguments. Most compilers won't complain if the function definition doesn't name those unused arguments.
About unnamed parameters in a declaration, which is the topic of this question: Just because doing this is legal doesn't necessarily mean it's a good practice. Those unnamed arguments in a function declaration might be fine for a compiler, but they aren't fine for a human reader. No name = zero communication. The documentation and header file should contain everything that an external user needs to know regarding how to use the class. RTFM and maybe RTFH (read the fine manual / read the fine headers). That "F" word ("fine") in RTFM and RTFH takes on a different meaning in RTFC.
Those unnamed arguments in a header are almost inevitably coupled with poor documentation. As an external user, this forces me to read the function's definition to understand how to use a function. RTFC. It is not fine when an external user has to read the implementation to determine what is going on.
That means that if you call it without passing parameters, the parameters will take the values you passed.
So if you call
IntSet* i = new Intset();
would be equivalent to calling
Intset* i = new IntSet(-1,-1,-1,-1)
About the unnamed part. I would assume because it is part of a library that uses templates. The nameless parameters are not used, but are there so it matches the signature of another class that may need them. In the case that it needs them, it will just pass -1 by default.
You can take a look at this link for an example:
http://compgroups.net/comp.lang.c++/unnamed-formal-parameter/1004784
I am copying the example from the above reference here, to make the case for using such a construct in an useful way
For instance
class A
{
public:
A(void* = 0) {} // unused parameter
};
class B
{
public:
B(void* p) : pp(p) {} // used parameter
private:
void* pp;
};
template <class T>
class C
{
public:
static T* create(void* p = 0) { return new T(p); }
};
int main()
{
A* a = C<A>::create();
B* b = C<B>::create("hello");
}
C::create would not compile unless A::A had a parameter even though it is
not used.