This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Why do multiple-inherited functions with same name but different signatures not get treated as overloaded functions?
This fails to compile in the indicated place with g++ 4.6.1:
enum Ea { Ea0 };
enum Eb { Eb0 };
struct Sa { void operator()(Ea) {} };
struct Sb { void operator()(Eb) {} };
struct Sbroken : Sa, Sb {};
struct Sworks {
void operator()(Ea) {}
void operator()(Eb) {}
};
int main() {
Sworks()(Ea0);
Sbroken()(Ea0); // g++ can't disambiguate Ea vs. Eb
}
Clang 2.8 does compile this code, which makes me uncertain if the code is really valid C++ or not. I was about to conclude optimistically that clang was right and g++ was wrong, but then I made a small change which made clang have a similar error:
enum Ea { Ea0 };
enum Eb { Eb0 };
struct Sa { void f(Ea) {} };
struct Sb { void f(Eb) {} };
struct Sbroken : Sa, Sb {};
struct Sworks {
void f(Ea) {}
void f(Eb) {}
};
int main() {
Sworks().f(Ea0);
Sbroken().f(Ea0); // both clang and g++ say this is ambiguous
}
The only change I made there was to use a named function f rather than operator(). I don't see why this should even matter, but it does: this version does not compile with g++ nor with clang.
I think it has something to do with hiding the function(s) in the base classes, and the GCC's error message doesn't seem to help much, even if you use struct instead of enum : In fact, the error message is misleading, because now Ea and Eb are two different classes, with no implicit conversion from Ea to Eb, the ambiguity shouldn't arise, but GCC seems to disagree with me : http://ideone.com/cvzLW (see the modification also).
Anyway, if you bring the functions in the class scope, explicitly by writing using as:
struct Sbroken : Sa, Sb
{
using Sa::operator();
using Sb::operator();
};
then it works : http://ideone.com/LBZgC
Same with other example as well:
struct Sbroken : Sa, Sb
{
using Sa::f;
using Sb::f;
};
Code : http://ideone.com/3hojd
Trying to understand the actual text in the standard (§10.2) isn't easy,
but there is an example which makes it clear: name lookup for a name x
in the derived class fails if the name isn't present in the derived
class, but it is present in more than one base class, and it isn't
hidden. (Hidden isn't relevant here, as it only intervenes when virtual
inheritance is present.) As far as I can tell, this is the case
regardless of the name of the member; I can find no exception if the
member happens to have the special name operator(). Overload
resolution doesn't come into play, because their is failure in the name
lookup, before the overload set is completely built. I'm pretty sure
that both snippets of code are illegal, and that there is a bug in
clang.
You can use using declarations to inject the names into the derived
class, or you can explicitly define forwarding operators in the derived
class. Once the name is found in the derived class, the compiler stops,
and does not look in the base classes.
Related
struct Test1 : public Base {
enum { type = 1 };
int a;
char ch;
virtual void func1();
};
struct Test2 : public Base {
enum { type = 2 };
int a;
char ch;
virtual void func1();
};
I'm developing a project with C++14. For some compatibility reason, I have to declare two classes as above, whose members are exactly the same.
My question is if there is some metaprogramming method, which allows me to check if the two classes have exactly the same members?
real issue
Yeah, I know it's so weird but I did get such an issue...
I'm developing a web server, each class above is a protocol.
Now the problem is that some Android developer has wrongly used the protocol Test1, so we can't touch it as users may not update their App. What I could do is just add another protocol. So I add the class Test2.
Since the two protocols do the exactly the samething, I want to make sure that they are always the same. Meaning that if someone adds a member into Test1 someday but he forgets to add the member into Test2, I want to get a compile-time error.
BTW, I only care about the data member, not member function.
Is it possible to check if two classes have the same members
If you can upgrade to C++20, and if the classes are standard layout, and you aren't concerned about exact matches for types, but rather layout compatibility - such that one class might have a const member while the other has non-const - then you can use the std::is_layout_compatible type trait.
Otherwise, you may have to resort to meta-programming.
I want to make sure that they are always the same.
Regarding the XY-problem, if you can change Test1 in an API compatible way, then inheritance could be a solution:
struct TestData : Base {
int a;
char ch;
};
template<int type>
struct TestBase : TestData {
enum { type = type };
};
struct Test1 : TestBase<1> {
void func1();
};
struct Test2 : TestBase<2> {
void func1();
};
If you cannot touch Test1 at all, then a hacky workaround would be to use it as a base:
struct Test2 : Test1 {
enum { type = 2 };
void func1();
};
It's not ideal due to the implicit conversions. You could avoid those by using private inheritance, but then you have the problem of shared public non-virtual Base.
I don't like the premise of this question because it is essentially asks for a way to keep code duplication. However in practice shit happens and if someone wants two classes with the same content the better idea would be not to declare two classes and then check them for compatibility, but to declare them just once. This can be done by using a base class or by using preprocessor. The latter case will also prevent any new members from sneaking into derived classes while adding new members into both classes with require just a single modification:
#define MAKE_CLASS(mp_name) \
struct mp_name : public Base { \
enum { type = 1 }; \
int a; \
char ch; \
void func1(); \
};
MAKE_CLASS(test1)
MAKE_CLASS(test2)
Whenever I try to compile my code I get an invalid use of auto. Coming from a Java background, I am not sure if I quite understand C++ templates. It seems like the compiler can infer the type. I am limited to C++11.
The error occurs in the GeneralRenderer.
Animal classes
class Animal {};
class Dog : public Animal {};
class Cat : public Animal {};
enum AnimalType {
Dog,
Cat
};
Render Classes
template<class T>
class AnimalRenderer {
virtual void draw(T entity) = 0;
};
class DogRenderer : public AnimalRenderer<Dog> {};
class CatRenderer : public AnimalRenderer<Cat> {};
Logic
class GeneralRenderer {
public:
void draw(
std::map<AnimalType, std::vector<Animal>> animalMap) {
for (auto entry: animalMap) {
AnimalRenderer<auto> renderer; // <--- Causes the error
switch (entry.first) {
case Dog:
renderer = DogRenderer();
break;
case Cat:
renderer = CatRenderer();
break;
}
for (auto animal: entry.second) {
renderer.draw(entry);
}
}
};
};
Informally speaking, auto can be used to declare and initialise a type at the same time. Then the compiler can infer the type from the value used to initialise the variable.
But that's not the case here; a statement like
auto n;
will fail similarly.
Note that auto merely stands in for a type that is known at compile time. It's there to make code more readable although its use is occasionally obligatory such as when working with lambda functions. It is not a variant-type construct cf. std::variant say of C++17.
Finally note that a std::map is a very different beast to a java.util.Map. There's no type erasure in C++ so a std::map<A, B> is a fundamentally different type to a std::map<C, D> if A is a different type to C and / or B differs from D. Furthermore, C++ allows you to store value types in maps.
As the other users already say, auto can‘t work without a righthand variable.
I think you should remove the template annotation from AnimalRenderer, then you can use the classes normally.
To get the result you want you effectively need to move the second for-loop inside the cases, where the deduction can be resolved for each case.
You don't want code duplication, so ideally you want a template function you can call to do the second loop. On the latest c++ standards you might also be able to declare a template lambda function.
That said, architecturally, I would suggest adding an interface base class for AnimalRenderer, and then you can declare a simple pointer to that base class, especially as you have already declared draw as virtual.
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'm working on a project where SFINAE is used to detect whether a member function exists. I'm running into a problem with the following example:
class Base
{
private:
template <class T>
void foo( T t ) {}
void snarf() {}
};
class Derived : public Base
{
public:
template <class T>
void bar( T t )
{
foo( t ); // shouldn't be possible
snarf(); // bug in gcc, correctly identified as error in clang
}
};
The problem seems to be that the access control (e.g. private) in the base class is not being respected in the derived class when trying to access inherited functions. Both foo and snarf should be inaccessible from the derived class. So when I try to test if some derived class has some function, it is incorrectly accessing the base class to find a match.
In g++ 4.8.1, both calling foo and snarf are incorrectly allowed to happen, which I'm pretty sure is an instance of this bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41437
In clang++ 3.3, calling snarf is correctly identified as an error, but foo is allowed to be called, which seems like it should also be an error. Does this look like a bug in clang++? (I've posted a bug report just in case it turns out to be http://llvm.org/bugs/show_bug.cgi?id=16410)
Given that this may well be a bug in both compilers, is there any clever workaround I can use to detect that derived doesn't really have access to foo? The way I'm actually using this is the following:
template <class T, class T2, class Unused = void>
struct has_member_foo : std::false_type {};
Where has_member_foo is specialized to extend from std::true_type when calling declval<T&>().foo(declval<T2&>()) resolves to a valid function ala Checking a member exists, possibly in a base class, C++11 version. I need this to fail when a derived class inherits a private version of foo.
What does the compiler say when you write code that attempts to call bar?
Derived d;
d.bar<int>(42);
If it displays an error there, then I think things are working as expected. Until you actually write code which uses a template method, there is nothing to compile, so you may not see any errors coming from it if you are using a less intelligent compiler.
You could even define bar like this:
template <class T>
void bar( T t )
{
foo( t );
snarf();
snorf();
divideByZero();
asdf--+|&*
}
And it will still compile (with some compilers), as long as you never try to use bar.
I have something similar to this in my code:
#include <iostream>
#include <cstdlib>
struct Base
{
virtual int Virtual() = 0;
};
struct Child
{
struct : public Base
{
virtual int Virtual() { return 1; }
} First;
struct : public Base
{
virtual int Virtual() { return 2; }
} Second;
};
int main()
{
Child child;
printf("ble: %i\n", ((Base*)&child.First)->Virtual());
printf("ble: %i\n", ((Base*)&child.Second)->Virtual());
system("PAUSE");
return 0;
}
I'd expect this to give this output:
ble: 1
ble: 2
and it does so, when compiled under GCC (3.4.5 I believe).
Compiling and running this under Visual Studio 2008 however, gives this:
ble: 2
ble: 2
What is interesting, is that if I give the Base-derived structs names (struct s1 : public Base), it works correctly.
Which behavior, if any, is correct? Is VS just being prissy, or is it adhering to the standard? Am I missing something vital here?
It appears this is a bug in VS 2008, possibly because it overwrites or ignores the vtable for the first unnamed class in favor of the vtable for the second since the internal names are identical. (When you name one explicitly, the internal names for the vtables are no longer identical.)
As far as I can tell from the standard, this should work as you expect and gcc is right.
It is visible how MSVC is getting it wrong from the debugging symbols. It generates temporary names for the anonymous structs, respectively Child::<unnamed-type-First> and Child::<unnamed-type-Second>. There is however only one vtable, it is named Child::<unnamed-tag>::'vftable' and both constructors use it. The different name for the vtable surely is part of the bug.
There are several bugs reported at connection.microsoft.com that are related to anonymous types, none of which ever made it to "must-fix" status. Not the one you found though, afaict. Maybe the workaround is just too simple.
I can confirm this is a known bug in the VC compiler (and it repos in VC10); the two anonymous classes are incorrectly sharing a vtable.
Anonymous structs are not part of the C++ standard.
Edit: Anonymous structs are kind of an ambiguous term. It can mean two things:
class outer
{
public:
struct {
int a;
int b;
} m_a; // 1
struct {
int c;
}; // 2
union {
int d;
int e;
}; // 3
};
1 is what is going on here, a better name than anonymous struct would be "unnamed struct". The struct type itself doesn't have a name, but the object does (m_a).
2 is also known as an anonymous struct, and isn't legal C++. There is no object name, and the idea is you could access the field 'c' directly on objects of type outer. This compiles only because of a compiler extension in Visual Studio (will fail under /Za)
3 Anonymous unions, by contrast, are legal C++.
I confused the two, because here we're calling #1 an "anonymous struct", and wires in my brain crossed with #2.