Question about ADL

D

derek

(Message also posted to comp.std.c++)

I have just been experimenting with g++ 3.4 and code that I thought was
compliant has raised compiler problems. Basically, if we have the
following code:

#include <iostream>

using std::cout;

template<typename T>
class A {
public:
T f() {return T();};
};

template<typename T>
class B : public A<T> {
public:
void g() {cout << f() << "\n";};
};

int main()
{
B<int> b;
b.g();
};


I would have expected the call to f() in g() to be OK. However, it isn't
for g++ 3.4:

checker.cc: In member function `void B<T>::g()':
checker.cc:14: error: there are no arguments to `f' that depend on a
template parameter, so a declaration of `f' must be available
checker.cc:14: error: (if you use `-fpermissive', G++ will accept your
code, but allowing the use of an undeclared name is deprecated)

Replacing f() with A<T>::f() will fix it. But is it a valid error, or is
g++ 3.4 wrong?

Thanks for any insights anyone can offer on this.

Derek
 
S

Sumit Rajan

(Message also posted to comp.std.c++)

I have just been experimenting with g++ 3.4 and code that I thought was
compliant has raised compiler problems. Basically, if we have the
following code:

#include <iostream>

using std::cout;

template<typename T>
class A {
public:
T f() {return T();};
};

template<typename T>
class B : public A<T> {
public:
void g() {cout << f() << "\n";};

A<T>::f() or this->f()

It has to do with the way non-dependent names are looked up -- they are not
looked up in dependent base classes but they still need to be looked up when
they are encountered. Using either of the techniques above, makes them
dependent names and hence delays the actual lookup till instantiation time.

Two phase lookup goes like this(roughly): In the first stage(while parsing),
non-dependent names are looked up using ordinary lookup rules (and ADL, if
needed). In the second phase (which happens when the templates are actually
instantiated), dependent qualified names are looked up.

};

int main()
{
B<int> b;
b.g();
};


You don't need the last ';'.



Regards,
Sumit.
 
D

derek

A<T>::f() or this->f()

Thanks said:
It has to do with the way non-dependent names are looked up -- they are not
looked up in dependent base classes but they still need to be looked up when
they are encountered.

So this is the key point: "they are not looked up in dependent base classes". So earlier versions of g++ were incorrect in doing so?
You don't need the last ';'.

I know - but old habits die hard and it does no harm. Consider it a personal idiosynchratic signature on my code!

Cheers

Derek
 
S

Sumit Rajan

Thanks, Sumit, for your comments. I realise that both of these approaches
work - also qualifying with B<T> works: B<T>::f(). I suppose that this last
example is the one that emphasises the reasons for my surprise most
strongly. If class B were to include a function, void h(), then one could
substitute h() for f() and get no compiler complaint. It seems as though
every function call to a non-virtual method could be considered to be
implicitly qualified with the class in which it is being used. It is very
stange, to me, that the scope for looking up f() does not include the base
class (as it did in earlier versions of the g++ compiler, at any rate).


Greetings Derek!

A<T>::f(), this->f(), B<T>::f() -- Any of these would make f() dependent.
Personally, I tend to prefer the first one since I find it most
reader-friendly. On your comment, "is very stange, to me, that the scope for
looking up f() does not include the base class": The is true of *dependent*
base classes. For example, consider the following:


#include <iostream>

class X {
public:
int f2(){return 45;}
};

template<typename T>
class B : public X {
T t;
public:
void g() {std::cout << f2() << '\n';}
};

int main()
{
B<int> b;
b.g();
}

Here X is a non-dependent base class.
In this case, the call the f2() works (you don't need to use this->f2() or
X::f2() ) perfectly since X is a non-dependent base.

So this is the key point: "they are not looked up in dependent base
classes". So earlier versions of g++ were incorrect in doing so?

Yes. I just tried your code with g++ 3.2. You are right: it does not
complain when I feed it your original case. But from what you say in your
original posting, it looks like that version 3.4 has fixed that.
I know - but old habits die hard and it does no harm. Consider it a
personal idiosynchratic signature on my code!

Ah! That's an truly original way of looking at it: a personal signature. :)

Regards,
Sumit.
 
A

Asfand Yar Qazi

int main()
personal idiosynchratic signature on my code!

Ah! That's an truly original way of looking at it: a personal signature. :)

I don't know about with functions, but gcc 3.4 now complains
about namespaces like the following:

namespace XX
{

}; // ERROR! BAD SEMI-COLON THINGY!
 
D

Dave Moore

(Message also posted to comp.std.c++)

I have just been experimenting with g++ 3.4 and code that I thought was
compliant has raised compiler problems. Basically, if we have the
following code:

#include <iostream>

using std::cout;

template<typename T>
class A {
public:
T f() {return T();};
};

template<typename T>
class B : public A<T> {
public:
void g() {cout << f() << "\n";};
};

int main()
{
B<int> b;
b.g();
};


I would have expected the call to f() in g() to be OK. However, it isn't
for g++ 3.4:

checker.cc: In member function `void B<T>::g()':
checker.cc:14: error: there are no arguments to `f' that depend on a
template parameter, so a declaration of `f' must be available
checker.cc:14: error: (if you use `-fpermissive', G++ will accept your
code, but allowing the use of an undeclared name is deprecated)

Replacing f() with A<T>::f() will fix it. But is it a valid error, or is
g++ 3.4 wrong?

I think that GCC 3.4.0 is correct to complain, because the compiler
cannot see a declaration of f() when it parses the code for class B.
c.f. section 14.6/1 of the Standard, which defines the types of names
that can be used within a template definition:
1) the name of the template itself, and names declared within it
2) names dependent on a template-parameter
3) names from visible scopes

the "naked" call to f() in the definition of class B does not meet any
of those criteria. Using the scope resolution operator (i.e.
A<T>::f() ) clears up this problem by making the declaration of f()
dependent on the template parameter T (c.f. 14.6.2.1/1).

HTH, Dave Moore
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top