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.
Related
This question is related to: C++: Explicitly call destructor of template parameter's typedef
I have the following:
class A {
public:
typedef std::shared_ptr<A> Ptr;
…
};
Later on, I have a variable ptr of type A::Ptr * obtained via placement new, essentially by a call to a function like this:
A::Ptr * f(A::Ptr obj) {
void * placement = get_legacy_storage(sizeof(obj));
return new(placement) A::Ptr(obj);
}
I now want to undo the placement-new with an explicit destructor call. I do it like this:
ptr->A::Ptr::~Ptr();
As remarked in a comment to an answer to the linked question, this works on gcc, but not with clang. § 12.4p13 of the standard says
In an explicit destructor call, the destructor name appears as a ~ followed by a type-name or decltype-specifier that denotes the destructor's class type.
but I'm unsure how this interacts with typedefs and scope resolution.
So, my questions are:
What are the C++-11 standards-compliant ways of explicitly calling the destructor in the above situation (ideally without revealing the type of Ptr)?
Do the answers for 1 work in gcc and/or clang? If not, what are the generally accepted workarounds?
With the minimized example
struct A {};
struct B {
using T = A;
};
int main() {
A* a = new A;
a->B::T::~T();
}
Godbolt indicates that Clang accepts the code as of version 11.
I'm not totally sure why Clang didn't accept this before, but perhaps it was related to a syntactic ambiguity which is discussed in more detail here.
The ambiguity is between
postfix-expression . templateopt id-expression
and
postfix-expression . pseudo-destructor-name
This ambiguity was resolved by P1131R2, and the resolution was voted as a DR; see CWG 2292. So I think that, even in C++11, the code should be considered valid.
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 made a class that has the same implementation of std::initializer_list using VS2013 that supports Uniform Initialization.
template <class _Elem>
class My_Initializer_List { ... } // Hope to replace std::initializer_list!
The first thing I've noticed is that the compiler keeps looking for std::initializer_list when it does have the substitute for it, which is My_Initiliazer_List.
void Foo()
{
// The compiler tries to invoke
// its constructor with std::initializer<int>{ 10, 20 }.
auto MyVar = My_Initializer_List<int>{ 10, 20 }; // Compile Error!
}
If this feature depends on the C++ Standard Library, then I believe that I should be able to replace it with my own class, at least for academic purposes.
Thanks in advance.
Sorry, but no. The compiler has special knowledge of std::initializer_list "baked in". The same is true of a few other parts of the standard library (e.g., a dynamic_cast of a reference throws a std::bad_cast, and there's not really anything you can do to change that either).
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
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.