C++ derived class member is ambiguous [duplicate] - c++

I'm getting the following compile error in one of my classes, using gcc 3.4.5 (mingw):
src/ModelTester/CModelTesterGui.cpp:1308: error: request for member `addListener' is ambiguous
include/utility/ISource.h:26: error: candidates are: void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SConsolePacket&]
include/utility/ISource.h:26: error: void utility::ISource<T>::addListener(utility::IListener<T>*) [with T = const SControlPacket&]
Hopefully you can see that ISource<T> is a template interface that just indicates that the object can be an informer for an object that is of some matching type IListener<T>. So the thing that has me irked is this idea that for some reason functions are ambiguous when, as far as I can tell, they are not. The addListener() method is overloaded for different input types IListener<const SConsolePacket&> and IListener<const SControlPacket&>. The usage is:
m_controller->addListener( m_model );
Where m_model is a pointer to an IRigidBody object, and IRigidBody inherits only from IListener< const SControlPacket& > and definately not from IListener< const SConsolePacket& >
As a sanity check, I used doxygen to generate the class hierarchy diagram and doxygen agrees with me that IRigidBody does not derive from IListener< const SConsolePacket& >
Evidently my understanding of inheritence in c++ is not exactly correct. I'm under the impression that IListener<const SControlPacket&> and IListener<const SConsolePacket&> are two different types, and that the function declarations
addListener(IListener<const SConsolePacket&>* listener)
and
addListener(IListener<const SControlPacket&>* listener)
declare two separate functions that do two separate things depending on the (distinct) different type of the parameter that is input. Furthermore, I'm under the impression that a pointer to an IRigidBody is also a pointer to an IListener<const SControlPacket&> and that by calling addListener( m_model ) the compiler should understand that I'm calling the second of the above two functions.
I even tried casting m_model like this:
m_controller->addListener(
static_cast<IListener<const SControlPacket&>*>(m_model) );
but still get that error. I cannot for the life of me see how these functions are ambiguous. Can anyone shed light on this issue?
P.S. I know how to force the function to be un-ambiguous by doing this:
m_controller->ISource<const SControlPacket&>::addListener( m_model );
I just happen to think that is terribly unreadible and I would prefer not to have to do that.
Edit... just kidding. That apparently doesn't fix the problem as it leads to a linker error:
CModelTesterGui.cpp:1312: undefined reference to `utility::ISource<aerobat::SControlPacket const&>::addListener(utility::IListener<SControlPacket const&>*)'

Looks like your situation is like this:
struct A {
void f();
};
struct B {
void f(int);
};
struct C : A, B { };
int main() {
C c;
c.B::f(1); // not ambiguous
c.f(1); // ambiguous
}
The second call to f is ambiguous, because in looking up the name, it finds functions in two different base class scopes. In this situation, the lookup is ambiguous - they don't overload each other. A fix would be to use a using declaration for each member name. Lookup will find names in the scope of C and don't lookup further:
struct C : A, B { using A::f; using B::f; };
Now, the call would find two functions, do overload resolution, and find that the one taking int will fit. Carried over to your code, it would mean that you have to do something like the following
struct controller : ISource<const SConsolePacket&>, ISource<const SControlPacket&> {
using ISource<const SConsolePacket&>::addListener;
using ISource<const SControlPacket&>::addListener;
};
Now, the two names are in the same scope, and now they can overload each other. Lookup will now stop at the controller class, not diving further into the two base-class branches.

Related

Conditionally defining method for container class

Is it possible (and is it a good idea) to conditionally define methods for some container class (template<typename ThingType> class Container) depending on the type of its elements? I first thought it was possible after reading about std::enable_if, but now I am not certain I understand.
Below is my attempt (click here to run on ideone). In the case that std::is_base_of<ThingBase, ThingType>::value is false, a return type for p will not be defined. I figured the compiler would just instantiate the object of a class without that method. But it turns out it doesn't compile.
Is there another tool for the job? Or should I write two Container-like classes that have different behavior depending on what ThingType is? Or maybe this is a job for a specialization.
#include <iostream>
#include <type_traits>
#include <vector>
class ThingBase {
public:
virtual void printHi() = 0;
};
class Thing : public ThingBase
{
void printHi(){
std::cout << "hi\n";
}
};
template<typename ThingType>
class Container{
private:
std::vector<ThingType> m_things;
public:
typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()
{
m_things[0].printHi();
};
};
int main() {
//Container<Thing> stuff; // works!
Container<int> stuff; // doesn't work :(
return 0;
}
Edits:
The error message from the compiler is
prog.cpp: In instantiation of ‘class Container<int>’:
prog.cpp:36:17: required from here
prog.cpp:26:78: error: no type named ‘type’ in ‘struct std::enable_if<false, void>’
typename std::enable_if<std::is_base_of<ThingBase, ThingType>::value>::type p()
#StoryTeller - Unslander Monica I don't intend for this method to be overloaded. I want it to be available to the end user whenever it makes sense for it to be available. There will only be one of these p methods, and it should take only one (relatively simple) signature.
I don't intend for this method to be overloaded. I want it to be available to the end user whenever it makes sense for it to be available. There will only be one of these p methods, and it should take only one (relatively simple) signature.
This simplifies the exercise quite a bit. The solution is... to do nothing special.
void p() {
m_things[0].printHi();
}
When a class template is implicitly instantiated, only the declarations of member function are instantiated along with it. Definitions are not instantiated until an attempt is made to use the member.
So you do not need to do anything special. The error will happen if it's used when it cannot be used.
If still you wish to ensure derivability, and produce a descriptive error in that case, you can add a static_assert to the member function body. Simply use the is_base_of test for a condition, and add a nice string to accompany it.
This is a common approach when writing generic utilities. SFINAE's primary purpose on the other hand is to control overload resolution. But you aren't doing it here.

this->field vs. this.field in C++

How do lines (2) and (3) even compile in the following C++ class, given that this is a pointer, so should need -> notation to access fields (as seen in line (1))? (Source)
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
template <typename T>
class sptr_wrapper
{
private:
boost::shared_ptr<T> sptr;
public:
template <typename ...ARGS>
explicit sptr_wrapper(ARGS... a)
{
this->sptr = boost::make_shared<T>(a...);
}
explicit sptr_wrapper(boost::shared_ptr<T> sptr)
{
this->sptr = sptr; // (1)
}
virtual ~sptr_wrapper() noexcept = default;
void set_from_sptr(boost::shared_ptr<T> sptr)
{
this.sptr = sptr; // (2)
}
boost::shared_ptr<T> get_sptr() const
{
return sptr; // (3)
}
};
The line (2) is invalid. As you said, this is a pointer, we need to use -> instead of .
As the member of class template, sptr_wrapper::set_from_sptr is not required to be instantiated, until it's used. So you can add some code trying to call it, then you might get compile-errors as you expect.
This applies to the members of the class template: unless the member is used in the program, it is not instantiated, and does not require a definition.
The line (3) is valid; sptr refers to the member sptr, which has the same effect as this->sptr.
When a non-static class member is used in any of the contexts where the this keyword is allowed (non-static member function bodies, member initializer lists, default member initializers), the implicit this-> is automatically added before the name, resulting in a member access expression (which, if the member is a virtual member function, results in a virtual function call).
Would you believe that the reason this compiles is because nothing really gets compiled here?
The shown code defines a template.
A template does not become "real" until it instantiates a class. Only at that time the compiler gets a closer look at the template, and attempts to figure WTF it's doing.
Sure, when defining a template the compiler makes a half-hearted attempt to parse the template, but only barely enough to satisfy itself that the template consists of some plausibly-looking C++ code.
If you add some additional lines to the shown code you'll get the compilation errors you were yearning for:
class X {};
void foo()
{
sptr_wrapper<X> x;
boost::shared_ptr<X> y;
x.set_from_sptr(y);
}
And this produces the compilation errors you were looking for:
t.C:27:14: error: request for member ‘sptr’ in ‘(sptr_wrapper<X>*)this’, which is of pointer type ‘sptr_wrapper<X>*’ (maybe you meant to use ‘->’ ?)
27 | this.sptr = sptr; // (2)
Note that merely instantiating
sptr_wrapper<X> x;
isn't enough. You have to go full throttle and invoke the method in question, before it becomes "real" in the eyes of a C++ compiler, and it chokes on it.
It's true that I can quite think of any circumstance where "this.foo" might be valid C++ code, but I'm sure that somewhere in the 2000 pages that make up the current C++ standard, the exact details of what's going on gets spelled out in a very pedantic way.
And you might consider dropping a note to your compiler's bug tracker, a feature request to have your compiler issue a friendly warning, in advance, when it sees something like this.

C++: "unresolved overload function type" between classes

This is probably something elementary, I have a function from one class (called cell) with identifier woo_func_ptr taking a pointer to function of type void with no arguments (void (*void_ptr)(void)) (which I typedef). In another class, I have an object of cell and I use the method woo_func_ptr. It won't allow me to, I get the error in the above title. If these two functions were not embedded inside a class, they would work fine
typedef void (*void_ptr)(void);
double WOO{0};
struct cell {
void woo_func_ptr(void_ptr jo)
{
jo();
}
};
class woosah
{
public:
void woo_func()
{
WOO+=rand();
std::cout << WOO << std::endl;
};
void run()
{
// other stuff
temp_cell.woo_func_ptr(woo_func);
// yet more stuff
}
cell temp_cell;
};
First of all pointer to woosah member function should be declared as
typedef void (woosah::*void_ptr)(void);
and then compiler would complain that it needs to see woosah definition while parsing this statement.
If you let compiler parse class woosah first by moving it up then it will complain that type cell is not defined (since it is contained within woosah). That wil still not solve your problem because of cyclic dependency while parsing.
One way is to solve cyclic dependency is by making temp_cell a pointer to cell instance and have it contained within woosah.
Also note, the syntax to call member function is by using .* or ->*
void run()
{
// other stuff
temp_cell->woo_func_ptr(temp_cell->*woo_func); // assuming temp_cell is pointer to some cell instance
// yet more stuff
}
http://msdn.microsoft.com/en-us/library/b0x1aatf(v=vs.80).aspx shows similar errors and their fixes.
A member function is not like a regular function. That's why there's a seperate "pointer to member function" type. It's because member functions are passed the implicit this pointer.
In fact, the standard even limits (severly) the casting of pointer to member function.
That's the source of your error.
You could use a static class function...
Change
void woo_func()
to
static void woo_func()
This will of coarse may not be what you want if you are trying to access data members of a particular object.
Member functions are kind of special and should not be treated as normal functions.

Ambiguous call if class inherits from 2 templated parent classes. Why?

I have a templated class that performs an action on the class that is given as template argument. For some of my classes I want to 'group' the functionality in one class, to make it easier for the caller. In fact the code looks something like this (names were changed):
template<typename T>
class DoSomeProcessing
{
public:
process(T &t);
};
class ProcessingFrontEnd : public DoSomeProcessing<CustomerOrder>, public DoSomeProcessing<ProductionOrder>
{
};
The problem is that when I call ProcessingFrontEnd::process with a CustomerOrder as argument, that the compiler complains about it.
I tried to reproduce the problem in a smaller test application. This is the code:
#include <vector>
class X : public std::vector<char>
, public std::vector<void *>
{
};
int main(void)
{
X x;
x.push_back('c');
return 0;
}
And indeed, if this is compiled, Microsoft's VS2010 compiler gives this error:
test.cpp
test.cpp(11) : error C2385: ambiguous access of 'push_back'
could be the 'push_back' in base 'std::vector<char,std::allocator<char> >'
or could be the 'push_back' in base 'std::vector<void *,std::allocator<void *> >'
test.cpp(11) : error C3861: 'push_back': identifier not found
I tested this test application with different types (char+void*, double+void*) and different arguments in the call ('c', 3.14), but the error message is always the same.
I tested this with VS2005 and VS2010 but I always get the same error.
Why can't the compiler determine the correct function to call? What makes this confusing for the compiler? Or is it just a bug in the Microsoft compiler?
EDIT:
If I explicitly add 2 push_back methods to my class, like this:
class X : public std::vector<char>
, public std::vector<void *>
{
public:
void push_back(char c) {}
void push_back(void *p) {}
};
The compiler doesn't complain anymore. So with these methods he can clearly distinguish between a character and a void-pointer. Why can't he do this if the two push_back methods are inherited from the parent?
This is by design. The compiler is not trying to resolve overloaded
functions because these are not overloaded
functions. The standard is really clear on that
(see 10.2.2). If the same name is found in two
different bases, it's an ambiguity, even if they
could be resolved correctly with the call (i.e. in
your case). Same-named functions in different classes will typically have quite different purposes and hence the selection between them should not be made on the basis of
their arguments. There are many good reasons not to
allow that, but here's one.
Imagine your class C derives from A and B and
these two base classes come from two different
libraries. If the author of B adds a new function
to the class, it may break the user's code by
redirecting a call from A::foo() to B::foo() if
the latter is a better match.
If you want the two functions to be treated in the same way that they would
be if part of a single class, then the best way to do it is with using
declarations in the derived class. Just add
using std::vector<char>::push_back;
using std::vector<void *>::push_back;
to the declaration of class X.
I believe you are running afoul of the C++ overloading rules which prohibit overloading across classes. You'd get the same results if your template classes were two separate classes, each with its own process(CustomerOrder) and process(ProductionOrder) member.
The workaround is explicit using statements inside your derived class, pulling in each overload from each of the template base classes.
How is the compiler supposed to know which process you want to call? There's two options. Do you want both, one, or the other?
You need to override process in the derived class.

boost::bind with protected members & context

In the below code, there are two "equivalent" calls to std::for_each using boost:bind expressions. The indicated line compiles, the indicated failing line fails. The best explanation I can find in the standard amounts to "because we said so". I'm looking for "why the standard indicates this behavior". My suppositions are below.
My question is simply: Why does the indicated line compile and the equivalent following line fail to compile (and I don't want because "the standard says so", I already know that - I will not accept any answers that give this as an explanation; I'd like an explanation as to why the standard says so).
Notes: Although I use boost, boost is irrelevant to this question, and the error in various formats has been reproduced using g++ 4.1.* and VC7.1.
#include <boost/bind.hpp>
#include <iostream>
#include <map>
#include <algorithm>
class Base
{
protected:
void foo(int i)
{ std::cout << "Base: " << i << std::endl; }
};
struct Derived : public Base
{
Derived()
{
data[0] = 5;
data[1] = 6;
data[2] = 7;
}
void test()
{
// Compiles
std::for_each(data.begin(), data.end(),
boost::bind(&Derived::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
// Fails to compile - why?
std::for_each(data.begin(), data.end(),
boost::bind(&Base::foo, this,
boost::bind(&std::map<int, int>::value_type::second, _1)));
}
std::map<int, int> data;
};
int main(int, const char**)
{
Derived().test();
return 0;
}
The indicated line fails with this error:
main.C: In member function 'void Derived::test()':
main.C:9: error: 'void Base::foo(int)' is protected
main.C:31: error: within this context
As noted, the supposedly equivalent statement above compiles cleanly (and if the offending statement is commented out, runs with the expected result of printing “5”, “6”, “7” on separate lines).
While searching for an explanation, I came across 11.5.1 in the standard (specifically, I’m looking at the 2006-11-06 draft):
An additional access check beyond
those described earlier in clause 11
is applied when a non-static data
member or nonstatic member function is
a protected member of its naming class
(11.2)105) As described earlier,
access to a protected member is
granted because the reference occurs
in a friend or member of some class C.
If the access is to form a pointer to
member (5.3.1), the
nested-name-specifier shall name C or
a class derived from C. All other
accesses involve a (possibly implicit)
object expression (5.2.5). In this
case, the class of the object
expression shall be C or a class
derived from C.
After reading this, it became evidently why the second statement failed while the first succeeded, but then the question came up: What is the rationale for this?
My initial thought was that the compiler was expanding the boost::bind templates, discovering that Base::foo was protected and kicking it out because boost::bind<…> was not a friend. But, the more I thought about this explanation, the less it made sense, because if I recall correctly, as soon as you take the pointer to a member (assuming you initially are within access control of the member), all access control information is lost (i.e. I could define a function that returns an arbitrary pointer to a member that alternately returns a public, protected or private member depending on some input and the returner would be none the wiser).
More I thought about it, and the only plausible explanation I could come up with why it should make a difference was in the case of multiple inheritance. Specifically, that depending on the class layout, the member pointer when calculated from Base would be different than that calculated from Derived.
It's all about "context". In the first call the context of the call is Derived which has access to the protected members of Base and hence is allowed to take addresses of them. In the second the context is "outside of" Derived and hence outside of Base so the protected member access is not allowed.
Actually, this seems logical. Inheritance gives you access to Derived::foo and not to Base::foo. Let me illustrate with a code example:
struct Derived : public Base
{
void callPrivateMethod(Base &b)
{
// this should obviously fail
b.foo(5);
// pointer-to-member call should also fail
void (Base::*pBaseFoo) (int) = &Base::foo; // the same error as yours here
(b.*pBaseFoo)(5);
}
};
The reason for this restriction is enforcement of access control across different classes that share a common base.
This is reinforced by notes in Core Language Defects Report defect #385, the relevant part copied here for reference:
[...] the reason we have this rule is that C's use of inherited protected members might be different from their use in a sibling class, say D. Thus members and friends of C can only use B::p in a manner consistent with C's usage, i.e., in C or derived-from-C objects.
As an example of something this rule prevents:
class B {
protected:
void p() { };
};
class C : public B {
public:
typedef void (B::*fn_t)();
fn_t get_p() {
return &B::p; // compilation error here, B::p is protected
}
};
class D : public B { };
int main() {
C c;
C::fn_t pbp = c.get_p();
B * pb = new D();
(pb->*pbp)();
}
The protected status of D::p is something we want the compiler to enforce, but if the above compiled that would not be the case.