In this sample code, there is two sentences showing the same static variable. The first one gives no ambiguity, but the second one does, why?
#include <iostream>
using namespace std;
struct A { static const char a = 'a'; };
struct B : public A { };
struct C : public A { };
struct G : public B, public C { };
int main()
{
G v;
cout << G::B::A::a << endl;
cout << v.B::A::a << endl;
}
GCC error (according to some comments, there's no ambiguity in clang):
main.cpp:15:18: error: 'A' is an ambiguous base of 'G'
cout << v.B::A::a << endl;
Code on coliru
This is clearly a bug in GCC, as a GCC maintainer recommends you report it. However, until it's fixed, you can use a nasty workaround like this:
std::cout << static_cast<B &>(v).A::a;
The advantage is this will help disambiguate if in a (complex) scenario that there are variables with the same name in one of the base classes.
Related
The following code compiles fine in g++.
#include <iostream>
#include <string>
using namespace std;
struct thing
{
int a;
char b;
string name;
};
int main()
{
thing t =
{
a : 23,
b : 'e',
name : "Hello"
};
cout << t.a << endl;
cout << t.b << endl;
cout << t.name << endl;
return 0;
}
I know that the C99 equivalent { .a = 23, .b = 'e', .name = "Hello" } is not supported in C++, but why is the above supported? Is it standardised? What is the name of this constructor idiom?
To put the above in perspective, if you have a system with a lot of immutable classes used for thread-safe messaging (all const and public members), then it is much easier to construct an instance of such a class using named members rather than writing a constructor and using positional arguments.
why does this code work? with c++14
// Example program
#include <iostream>
#include <string>
using namespace std;
auto fun()
{
struct a
{
int num = 10;
a()
{
cout << "a made\n";
}
~a()
{
cout << "a destroyed\n";
}
};
static a a_obj;
return a_obj;
}
int main()
{
auto x = fun();
cout << x.num << endl;
}
how is the type a visible in main? if i change auto x= to a x= it obviously doesn't compile, but how does main know about the type a?
The static declaration is there since I was trying to test for something else but then I stumbled upon this behavior.
Running it here: https://wandbox.org/permlink/rEZipLVpcZt7zm4j
This is all surprising until you realize this: name visibility doesn't hide the type. It just hides the name of the type. Once you understand this it all makes sense.
I can show you this without auto, with just plain old templates:
auto fun()
{
struct Hidden { int a; };
return Hidden{24};
}
template <class T> auto fun2(T param)
{
cout << param.a << endl; // OK
}
auto test()
{
fun2(fun()); // OK
}
If you look closely you will see this is the same situation as yours:
you have a struct Hidden which is local to fun. Then you use an object of type Hidden inside test: you call fun which returns a Hidden obj and then you pass this object to the fun2 which in turn has no problem at all to use the object Hidden in all it's glory.
as #Barry suggested the same thing happens when you return an instance of a private type from a class. So we have this behavior since C++03. You can try it yourself.
C++14 is made to be more and more tolerant with auto. Your question is not clear, because you're not stating what the problem is.
Now let's tackle your question differently: Why does it not work with a x = ...?
The reason is that the struct definition is not in the scope of the main. Now this would work:
// Example program
#include <iostream>
#include <string>
using namespace std;
struct a
{
int num = 10;
};
auto fun()
{
static a a_obj;
return a_obj;
}
int main()
{
a x = fun();
cout << x.num << endl;
}
Now here it doesn't matter whether you use a or auto, because a is visible for main(). Now auto is a different story. The compiler asks: Do I have enough information to deduce (unambiguously) what the type of x is? And the answer is yes, becasue there's no alternative to a.
While trying to understand the phrase "constructors do not have names" in the C++ Standard, it seems like I found an error in clang. Could someone confirm this?
VS2015 and gcc rejects this code, and I think they it are is correct. At least, this is the impression I get from §12.1[class.ctor]/2 in N4140:
#include <iostream>
class A {
public:
A() { std::cout << "A()" << '\n'; }
};
int main()
{
A::A();
}
§12.1[class.ctor]/2 in N4140:
A constructor is used to initialize objects of its class type. Because
constructors do not have names, they are never found during name
lookup; ...
With the expression A::A(); above, clang finds the constructor by name lookup, when it should find the type name A instead. See live example.
Your intuition is correct. This is a known Clang bug 13403 with status NEW.
I agree that this should not compile.
It's actually more bizzare than you thought. Try this:
#include <iostream>
#include <string>
class A {
public:
A() {
std::cout << "A() " << this << '\n';
}
void foo() {
std::cout << _message << std::endl;
}
std::string _message = "hello";
};
int main()
{
A::A().foo();
}
example output:
A() 0x7fff5cd105f8
hello
It looks to me as if an un-named A is being implicitly created.
Consider the problem of getting an object as argument and printing its type:
#include <iostream>
class A { };
class B : public A { };
class C : public A { };
class D : public C, public B { };
using namespace std;
template<class T>
void print_type(T* info)
{
if(dynamic_cast<D*>(info))
cout << "D" << endl;
else if(dynamic_cast<C*> (info))
cout << "C" << endl;
else if(dynamic_cast<B*>(info))
cout << "B" << endl;
else if(dynamic_cast<A*> (info))
cout << "A" << endl;
}
int main(int argc, char** argv)
{
D d;
print_type(&d);
return 0;
}
It gives me the following error: "Ambiguous conversion from derived class 'D' to base class."
But I fail to see where's the ambiguity: if the object declared in main (d) is of type D, why can't be it directly converted to a type A?
Also, if I pass an argument of type string of course I get other errors:
'std::basic_string<char>' is not polymorphic
In Java for generics there is the syntax: <T extends A>; in this case it would be useful. How can I make a similar thing in C++ with templates?
I have modified the code this way:
#include <iostream>
#include <vector>
class A { };
class B : virtual public A { };
class C : virtual public A { };
class D : public C, public B { };
using namespace std;
template<class T>
void print_type(T* info)
{
if(dynamic_cast<D*>(info))
cout << "D" << endl;
else if(dynamic_cast<C*> (info))
cout << "C" << endl;
else if(dynamic_cast<B*>(info))
cout << "B" << endl;
else if(dynamic_cast<A*> (info))
cout << "A" << endl;
}
int main(int argc, char** argv)
{
string str;
print_type(&str);
return 0;
}
But I still get the error: 'std::basic_string<char>' is not polymorphic
First of all, this is not a templates problem. If you remove the template and just have print_type take a D*, you'll see that the error will still be there.
What is happening is you do not use virtual inheritance, hence you get this situation:
A A
| |
B C
\ /
D
The dynamic_cast doesn't know which A you are refering to.
To achieve this: (and I assume it's what you wanted)
A
/ \
B C
\ /
D
...you should use virtual inheritance, ergo:
class A
{
};
class B : virtual public A
{
};
class C : virtual public A
{
};
class D : public C,public B
{
};
... and now it compiles without problems :) (keep in mind that Virtual Inheritance Is Evil though)
This is called a deadly diamond of death, or simply, diamond problem. The "path" to A can go through either B or C, hence a potential contradiction.
Furthermore, the idea of a template is to make it generic, not type aware. A template is not in itself compiled code, it's compiled against its use. It's a lot like a big macro.
Consider the problem of getting an object as argument and printing it's type:
Sigh... use RTTI.
#include <iostream>
#include <string>
#include <typeinfo>
template<class T> void print_type(const T& info){
std::cout << typeid(info).name() << std::endl;
}
int main(int argc, char** argv){
D d;
int a = 3;
std::string test("test");
print_type(d);
print_type(a);
print_type(test);
return 0;
}
I need to print the type of a parameter in a C++ source file using the clang API.
If I have a parameter representation in clang (ParmVarDecl* param) I can print the name of the parameter using param->getNameAsString(). I would need a method param->getTypeAsString(), but there is no such method. So is there another way to do this task?
Got the answer to my question in the llvm irc:
There is a method std::string clang::QualType::getAsString(SplitQualType split)
So this does work for me:
ParmVarDecl* param = *someParameter;
cout << QualType::getAsString(param->getType().split()) << endl;
You can use typeid to get the name of any type. Although it will vary from compiler to compiler, and may not be a pretty name.
#include <iostream>
#include <typeinfo>
struct MyStruct { };
int main()
{
std::cout << typeid(MyStruct).name() << std::endl;
}
If you need to do this for a lot of classes, you could make the call part of a base class, then any class that needs the functionality can just inherit from it.
#include <iostream>
#include <typeinfo>
class NamedClass
{
public:
virtual ~NamedClass() { }
std::string getNameAsString()
{
return typeid(*this).name();
}
};
class MyStruct : public NamedClass
{
};
int main()
{
MyStruct ms;
std::cout << ms.getNameAsString() << std::endl;
}