I have a structure like this, with struct Baz inheriting from 2 different structs, Foo and Bar.
I have 2 methods called the same thing, one with a parameter of Foo and one with a parameter of Baz.
struct Foo
{
};
struct Bar
{
};
struct Baz : Foo, Bar
{
virtual void something(const Foo& foo)
{
};
virtual void something(const Bar& bar)
{
};
};
I call it like this
Baz baz;
baz.something(baz);
And understandably I have an issue with my code knowing which function I am calling if I pass it an instance of Baz. I get “Ambiguous call to overloaded function”.
I know I can cast my Baz to Foo or Bar to resolve the issue...
Baz baz;
baz.something((Bar)baz);
...but is there another way of dealing with this design issue?
I want to call the Foo method ONLY if the object being passed is not of type Bar.
edit:
If this was C# (which it isn't) I could probably solve this using a template where clause.
First off, note that the cast you've used would create a temporary object. You probably meant this:
baz.something(static_cast<Bar&>(baz));
And to answer your question, it should be possible to use SFINAE for this:
struct Baz : Foo, Bar
{
virtual void something(const Bar &bar)
{ /* ... */ }
template <
class T,
class = typename std::enable_if<
std::is_convertible<const T&, const Foo&>::value &&
!std::is_convertible<const T&, const Bar&>::value
>::type
>
void something (const T &foo)
{ something_impl(static_cast<const Foo&>(foo)); }
private:
virtual void something_impl(const Foo &foo)
{ /* ... */ }
};
Live example
Related
Given the following class:
class Foo
{
public:
//...
private:
Bar mBar;
};
Is it possible to expose the mBar member in such a way that it's members can be accessed, but not the mBar object itself?
The reason is that users should be able to access all of mBar's members but they should not be able to assign another Bar instance to mBar.
Bar has a lot of members and it would be cumbersome to write getters/setters and forwarding fuctions for them all. But if mBar is made public one is able to do aFoo.mBar = Bar(/*...*/);which is the only thing that should not be allowed.
Deleting Bar's assignment operators is not an option.
if you only want to protect against errors and not Machiavelli, operator-> might help (you might probably want a wrapper instead of directly put it in foo though):
class Foo
{
public:
//...
const Bar* operator ->() const { return &mBar; }
Bar* operator ->() { return &mBar; }
private:
Bar mBar;
};
so
Foo foo;
foo->bar_member;
foo.foo_member;
// Machiavelli
*foo.operator->() = Bar();
I would probably rethink your design but here is a possible indirect way using an intermediate get method:
struct Bar {
int intAttr;
};
class Foo {
Bar mBar;
public:
template <class U>
U& get(U Bar::* p) {
return mBar.*p;
}
};
This way, you can access any public member of mBar using:
Foo foo;
foo.get(&Bar::intAttr); // get
foo.get(&Bar::intAttr) = 0; // set
When I inherit from a class the compiler has to know the definition of the base class in order to create it. But when I inherit from a template class using oneself (the inheriting class), how can the compiler create the code? It does not know the size of the class yet.
#include <iostream>
template <class T> class IFoo
{
public:
virtual T addX(T foo, double val) = 0;
// T memberVar; // uncomment for error
};
class Foo : public IFoo<Foo>
{
public:
Foo(double value)
: m_value(value) {}
Foo addX(Foo foo, double b) override
{
return Foo(foo.m_value + b);
}
double m_value;
};
int main()
{
Foo foo1(1);
Foo foo2 = foo1.addX(foo1, 1);
std::cout << foo2.m_value;
}
First I thought it works because it's an interface but it also works with a regular class.
When I store the template as a member i get an error that Foo is undefined, just as I expected.
The general concept here is called the Curiously Recurring Template Pattern or CRTP. Searching on that will get lots of hits. see: https://stackoverflow.com/questions/tagged/crtp .
However there is a simple explanation that likely answers your question without getting too much into CRTP. The following is allowed in C and C++:
struct foo {
struct foo *next;
...
};
or with two types:
struct foo;
struct bar;
struct foo {
struct bar *first;
...
};
struct bar {
struct foo *second;
...
};
So long as only a pointer to a struct or class is used, a complete definition of the type doesn't have to be available. One can layer templates on top of this in a wide variety of ways and one must be clear to reason separately about the type parameterizing the template and its use within the template. Adding in SFINAE (Substitution Failure Is Not An Error), one can even make templates that do no get instantiated because things cannot be done with a given type.
With this definition of template class IFoo, the compiler does not need to know the size of Foo to lay out IFoo<Foo>.
Foo will be an incomplete class in this context (not "undefined" or "undeclared") and usable in ways that any incomplete type can be used. Appearing in a member function parameter list is fine. Declaring a member variable as Foo* is fine. Declaring a member variable as Foo is forbidden (complete type required).
how can the compiler create the code?
Answering this question would be the same as answering this question: How can the compiler compile that?
struct Type;
Type func(Type);
Live example
How can you define a type that doesn't exist and yet declare a function that use that type?
The answer is simple: There is no code to compile with that actually use that non-existing type. Since there is no code to compile, how can it even fail?
Now maybe you're wondering what is has to do with your code? How does it make that a class can send itself as template parameter to it's parent?
Let's analyze what the compiler see when you're doing that:
struct Foo : IFoo<Foo> { /* ... */ };
First, the compile sees this:
struct Foo ...
The compiler now knows that Foo exists, yet it's an incomplete type.
Now, he sees that:
... : IFoo<Foo> ...
It knows what IFoo is, and it knows that Foo is a type. The compiler now only have to instanciate IFoo with that type:
template <class T> struct IFoo
{
virtual T addX(T foo, double val) = 0;
};
So really, it declares a class, with the declaration of a function in it. You saw above that declaring a function with an incomplete type works. The same happens here. At that point, Your code is possible as this code is:
struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
So really there's no sorcery there.
Now let's have a more convincing example. What about that?
template<typename T>
struct IFoo {
void stuff(T f) {
f.something();
}
};
struct Foo : IFoo<Foo> {
void something() {}
};
How can the compiler call something on an incomplete type?
The thing is: it don't. Foo is complete when we use something. This is because template function are instantiated only when they are used.
Remember we can separate functions definition even with template?
template<typename T>
struct IFoo {
void stuff(T f);
};
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
struct Foo : IFoo<Foo> {
void something() {}
};
Great! Does it start looking exactly the same as your example with the pure virtual function? Let's make another valid transformation:
template<typename T>
struct IFoo {
void stuff(T f);
};
struct Foo : IFoo<Foo> {
void something() {}
};
// Later...
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
Done! We defined the function later, after Foo is complete. And this is exaclty what happens: The compiler will instanciate IFoo<Foo>::stuff only when used. And the point where it's used, Foo is complete. No magic there either.
Why can't you declare a T member variable inside IFoo then?
Simple, for the same reason why this code won't compile:
struct Bar;
Bar myBar;
It doesn't make sense declaring a variable of an incomplete type.
I have a struct of Foo:
struct Foo
{
};
I have a struct of Bar:
struct Bar
{
};
They are handled by 2 more structs which maintain (add/remove) a pointer array of each:
struct FooContainer
{
Foo** FooList;
// add(), remove() etc
};
struct BarContainer
{
Bar** BarList;
// add(), remove() etc
};
Now, what I WANT is another struct called Baz which links (in a one-to-many fashion) Foo to Baz. I can't (for reasons not explained here) refer to them by index, it must be by pointer/reference.
Something like this:
struct Baz
{
Foo* foo;
Bar* bar;
};
If I wanted to add a constructor to Baz which took these non-const pointers, how would I do it?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
Do I pass the pointers into the constructor as const and then do something with them as I would if I were passing a reference to a struct? I then get issues with trying to set the value of a non-const pointer to a const pointer.
I hope this question makes sense...
Edit: Should I use reference instead of pointer?
Baz should allow me to change which instance of Foo and Bar it points to... so it's pointers don't want to be const.
That is correct, you don't want to store constant pointers. However, it does not prevent you to store pointers to const, which is not the same thing.
This sounds confusing, so here is an illustration using your Baz example:
struct Baz
{
const Foo* foo;
const Bar* bar;
Baz(const Foo* newFoo, const Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(const Foo* newFoo) { foo = newFoo; }
void setBar(const Bar* newBar) { bar = newBar; }
};
everything is going to compile fine: it's Foo and Bar pointed to by foo and bar that are const, not the pointers themselves, which leaves you free to change the pointers as you wish.
This, on the other hand, is not going to compile:
struct Baz
{ // Note how const has moved to the other side of the asterisk
Foo* const foo;
Bar* const bar;
Baz(Foo* newFoo, Bar* newBar) : foo(newFoo), bar(newBar) {}
void setFoo(Foo* newFoo) { foo = newFoo; } // BROKEN!!!
void setBar(Bar* newBar) { bar = newBar; } // BROKEN!!!
};
Now the pointer, not the "pointee", is const, preventing you from changing foo or bar members.
For example, I have two classes
class Foo;
class Bar;
class Foo {
const Bar &m_bar;
...
};
class Bar {
const Foo &m_foo;
...
};
Let foo is object of Foo and bar is object of Bar. Is there any way (normal or "hacking") to create/initialize foo and bar that their members m_bar and m_foo would referenced to each other (I mean foo.m_bar is bar and bar.m_foo is 'foo')?
It is allowed to add any members to Foo and Bar, to add parents for them, to make they templates and so on.
What is the linkage of foo and bar? If they have external
linkage, you can write something like:
extern Foo foo;
extern Bar bar;
Foo foo( bar );
Bar bar( foo );
(I'm assuming here that it is the constructors which set the
reference to a parameter.)
This supposes namespace scope and static lifetime, of course
(but an anonymous namespace is fine).
If they are class members, there's no problem either:
class Together
{
Foo foo;
Bar bar;
public:
Together() : foo( bar ), bar( foo ) {}
};
If they're local variables (no binding), I don't think there's
a solution.
EDIT:
Actually, the local variables have a simple solution: just
define a local class which has them as members, and use it.
This can't work if i understand your Problem correctly, since to create an Object Bar you need Foo and vice versa.
You must not use References but an Pointer instead. Where you can create both Objects separatley and then set Bar to Foo and Foo to Bar.
class Foo
{
public:
Foo();
void setBar( const Bar* bar ){ _bar = bar; }
private:
const Bar* _bar;
}
// class Bar analog to Foo
void xxx:something(void)
{
Foo* f = new Foo;
Bar* b = nee Bar;
f->setBar(b);
b->setBar(f);
...
}
I am stumped by why the declaration of void operator()(int) in the base class in the code sample below is seemingly hidden when the derived class implements void operator()(int,int,int). How can I get the declaration of operator()(int) from the base class foo to be visible in the derived class bar? That is, how can I modify the example so that the invocation of operator()(int) works?
#include <iostream>
struct foo
{
void operator()(int)
{
std::cout << "A" << std::endl;
}
};
struct bar : foo
{
// If this is uncommented, the code will not compile.
// void operator()(int, int, int) {}
};
int main()
{
bar b;
b(1);
return 0;
}
When compiled with g++ with the marked lines uncommented, the error message is along the lines of "no match for call to 'bar (int)' ... candidate is void bar::operator()(int,int,int) ... candidate expects 3 arguments, 1 provided."
That's right. Derived class functions hide base class functions rather than overloading. The fix is pretty simple though:
struct bar : foo
{
using foo::operator();
void operator()(int, int, int) {}
};
Note that operator() might make this look more confusing than it is. The classic example would probably be something more like bar::mymethod(int) and foo::mymethod(). The derived method hides the inherited method because of how resolution happens. The using declaration explained in another answer brings in foo's method for resolution.