I don't understand why the compiler balks at the following:
//---------begin code -----------
template <typename T>
struct Base {
void foo() const {}
};
struct Derived : public Base<Derived> {
void foo(const int arg) const {}
};
int main(){
Derived d;
d.foo(15);
d.foo(); //won't compile... says that the "only candidate function
is void Derived::foo(int) "
}
//-----------end code -----------
It seems to me that the Derived::foo(int) should not hide Base::foo(),
but that's what appears to be happening. I've tried compiling with
IRIX gcc and Linux g++.
Can anyone explain why the compiler won't allow this?
Thanks in advance,
Daniel
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
the.doag (5)
|
5/14/2007 9:52:49 PM |
|
Daniel wrote:
> I don't understand why the compiler balks at the following:
>
> //---------begin code -----------
> template <typename T>
> struct Base {
> void foo() const {}
> };
>
> struct Derived : public Base<Derived> {
> void foo(const int arg) const {}
> };
>
> int main(){
> Derived d;
> d.foo(15);
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "
> }
> //-----------end code -----------
>
> It seems to me that the Derived::foo(int) should not hide Base::foo(),
> but that's what appears to be happening. ...
Derived names always hide base names. See below.
> Can anyone explain why the compiler won't allow this?
From 10.2/2:
"... First, every declaration for the name in the class and in each of
its base class sub-objects is considered. A member name f in one
subobject B hides a member name f in a sub-object A if A is a base class
sub-object of B. Any declarations that are so hidden are eliminated from
consideration. ..."
If you assign a Base reference to d, then you can call foo() through
that reference, because the derived class isn't considered then. You
could also qualify foo() with Base, so that it calls the right function:
Derived d;
Base & b = d;
b.foo(); // <- okay, Base::foo() is the only name considered
d.foo(15); // <- okay, Derived::foo(int)
d.foo(); // <- *error*, Derived::foo(int) hides B::foo()
d.Base::foo(); // <- okay, calls Base's foo()
--
John Moeller
fishcorn@gmail.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
5/15/2007 12:59:18 PM
|
|
On Mon, 14 May 2007, Daniel wrote:
> I don't understand why the compiler balks at the following:
>
> //---------begin code -----------
> template <typename T>
> struct Base {
> void foo() const {}
> };
>
> struct Derived : public Base<Derived> {
> void foo(const int arg) const {}
> };
>
> int main(){
> Derived d;
> d.foo(15);
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "
> }
> //-----------end code -----------
>
> It seems to me that the Derived::foo(int) should not hide Base::foo(),
> but that's what appears to be happening. I've tried compiling with
> IRIX gcc and Linux g++.
This has nothing to do with CRTP, it's the simple rules of hiding in
normal derivation.
struct Base
{
void foo() {}
};
struct Derived : Base
{
void foo(int i) {}
};
int main()
{
Derived d;
d.foo(16); // works
d.foo(); // fails
}
This came up perhaps two weeks ago. When the compiler finds a name it the
derived class, it does overload resolution based on that alone and doesn't
bother to check the base classes, unless the derived class contains a
using declaration for the name.
The reason is to reduce surprises for the programmer introduced by
overloads in deep bases. Consider:
struct Base1
{
void foo(int i) {}
};
struct Base2 : Base1 { };
// Much code that blurs the relations.
struct Derived : BaseN
{
void foo(double d) {}
};
int main()
{
Derived d;
d.foo(100); // Expects Derived::foo(double) to be called.
}
If the compiler always considered all bases, the programmer would have to
first check that no class in the base graph contains any other function
called foo. That's not a good assumption. Basically, a programmer should
know, only by looking at the most derived class, which function is called
(or at least that he definitely needs to look in the base classes).
The way it is, the behaviour meets the expectation: Derived::foo(double)
is indeed called.
Sebastian Redl
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Sebastian
|
5/15/2007 1:02:37 PM
|
|
Daniel wrote:
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "
> }
> //-----------end code -----------
>
> It seems to me that the Derived::foo(int) should not hide Base::foo(),
> but that's what appears to be happening. I've tried compiling with
> IRIX gcc and Linux g++.
>
> Can anyone explain why the compiler won't allow this?
>
Because the only overload for Derived::foo is one that takes an int.
Let me give you a brief lesson on how functions work in C++:
1. First the name is looked up (Derived::foo)
2. Then the overloads for this name are checked (only foo(int))
3. Then the access is checked for that overload
4. Then if virtual, the final overrider is selected.
Defining a name in the Derived class hides anything else with that
name in base classes. If you want to bring forward a name from the
base class, you must do so explicitly:
struct Derived : Base {
using Base::foo;
void foo(int);
};
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Ron
|
5/15/2007 1:03:11 PM
|
|
On May 15, 6:52 am, Daniel <the.d...@gmail.com> wrote:
> I don't understand why the compiler balks at the following:
>
> template <typename T>
> struct Base {
> void foo() const {}
> };
>
> struct Derived : public Base<Derived> {
> void foo(const int arg) const {}
> };
>
> int main(){
> Derived d;
> d.foo(15);
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "}
>
> It seems to me that the Derived::foo(int) should not hide Base::foo(),
Oh, but it does. function lookup stops in the first class that has a
member function of the given name, no matter what arguments that
function takes.
To solve your problem you need to add
using Base<Derived>::foo;
within the definition of Derived.
Cheers,
Nicola Musatti
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Nicola
|
5/15/2007 1:03:21 PM
|
|
Daniel wrote:
> I don't understand why the compiler balks at the following:
>
> //---------begin code -----------
> template <typename T>
> struct Base {
> void foo() const {}
> };
>
> struct Derived : public Base<Derived> {
> void foo(const int arg) const {}
> };
>
> int main(){
> Derived d;
> d.foo(15);
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "
> }
> //-----------end code -----------
>
> It seems to me that the Derived::foo(int) should not hide Base::foo(),
> but that's what appears to be happening. I've tried compiling with
> IRIX gcc and Linux g++.
>
> Can anyone explain why the compiler won't allow this?
>
> Thanks in advance,
> Daniel
>
>
As I answered in the other forum you posted it in, Derived::foo
is indeed supposed to hide Base::foo. A name declared in a derived
class always hides the same name in the base class.
Adding
using Base::foo;
to the Derived class will bring it forward.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Ron
|
5/15/2007 1:03:51 PM
|
|
On May 15, 7:52 am, Daniel <the.d...@gmail.com> wrote:
> I don't understand why the compiler balks at the following:
>
> //---------begin code -----------
> template <typename T>
> struct Base {
> void foo() const {}
>
> };
>
> struct Derived : public Base<Derived> {
Add this line:
using Base<Derived>::foo;
> void foo(const int arg) const {}
>
> };
>
> int main(){
> Derived d;
> d.foo(15);
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "}
>
> //-----------end code -----------
This problem popped up a few times recently -- try to google this
group for more elaborate answer.
--
Regards,
Alex
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Alex
|
5/15/2007 1:39:03 PM
|
|
Daniel wrote:
> I don't understand why the compiler balks at the following:
>
> //---------begin code -----------
> template <typename T>
> struct Base {
> void foo() const {}
> };
>
> struct Derived : public Base<Derived> {
> void foo(const int arg) const {}
> };
>
> int main(){
> Derived d;
> d.foo(15);
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "
> }
> //-----------end code -----------
>
> It seems to me that the Derived::foo(int) should not hide Base::foo(),
> but that's what appears to be happening. I've tried compiling with
> IRIX gcc and Linux g++.
By overloading (not overriding) functions in a derived class, you hide all
functions of the base class with the same name that you don't override.
Add the following to the Derived class definition to override that
behaviour:
using Base::foo;
--
Thomas
http://www.netmeister.org/news/learn2quote.html
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Thomas
|
5/15/2007 1:39:15 PM
|
|
Daniel <the.doag@gmail.com> writes:
> //---------begin code -----------
> template <typename T>
> struct Base {
> void foo() const {}
> };
>
> struct Derived : public Base<Derived> {
> void foo(const int arg) const {}
> };
>
> int main(){
> Derived d;
> d.foo(15);
> d.foo(); //won't compile... says that the "only candidate function
> is void Derived::foo(int) "
> }
> //-----------end code -----------
>
> It seems to me that the Derived::foo(int) should not hide
> Base::foo(), but that's what appears to be happening.
As it should. Overloading occurs within scopes. Once the name foo has
been found in a scope, lesser scopes are not considered.
A using declaration helps:
struct Derived : public Base<Derived> {
void foo(const int arg) const {}
using Base<Derived>::foo;
};
Now Base<Derived>::foo() and Derived::foo(int arg) (the const is just
a comment here) are found simultaneously, and overload resolution will
cause Base<Derived>::foo() to be selected if no argument is passed.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Thomas
|
5/15/2007 1:39:22 PM
|
|
Daniel wrote:
>
> Can anyone explain why the compiler won't allow this?
>
> Thanks in advance,
> Daniel
>
>
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Road
|
5/15/2007 1:42:29 PM
|
|
John Moeller wrote:
> Base & b = d;
Oops, this should be Base<Derived>, not Base.
--
John Moeller
fishcorn@gmail.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
John
|
5/15/2007 9:25:14 PM
|
|
|
10 Replies
93 Views
(page loaded in 0.198 seconds)
Similiar Articles: Implementing a mangling tool - comp.lang.c++.moderatedFor those with no requirement for context info, it ... entire program, run the code generator, re-compile function ... Implementing Feature X in C++, Part 1 | Overloading ... cannot write std::map via ostream_iterator? - comp.lang.c++ ...... g++/bits/stream_iterator.h: In member function ... (Or perhaps it has to do with the context of the ... tell me why the program below does not compile? GCC says: [error ... nitializing a static vector <> of integers (this static vector... int signal, siginfo_t* info = 0, void* context = 0) = 0 ... [] operator on vector is overloaded and is _not_ as simple as ... in memory. it completely depends on the compiler you are ... ptr versus const ptr& - comp.lang.c++.moderatedSame as other assignment operator overload: use a temporary and swap with it. ... const reference typedef compile error: - comp ... Examples of C++ in Safety Critical Systems - comp.lang.c++ ...But the context of Scott's question was clearly C++ ... Note that Ada allows overload resolution based upon ... What if there is an error in the compiler, and it generates ... Const constructor - comp.lang.c++.moderatedaggregate<int> const ac(a) ; *ac = 7 ; // compile error ... They overload[] and have a .size() member: Array ... You can write functions which take an Array to ... Dos and don'ts in C++ unit testing? - comp.lang.c++.moderated ...The compiler is unlikely > to pick up ... yes, but only if a class has overloaded member functions with ... so in the process of creating a context for that function to ... c++ - Typedef compilation error on function overload - Stack OverflowTypedef compilation error on function overload ... are not - int has no context associated ... CRTP-related compiler error on typedef C++ SFINAE with CRTP, G++ compile error - Stack Overflow... with one parameter, so the overload ... are not allowed in this context Edit ... CRTP-related compiler error on pointer-to-a-member-function default value 7/17/2012 9:35:25 PM
|