Question about ADL

Discussion in 'C++' started by derek@cis.strath.ac.uk, Apr 29, 2004.

  1. Guest

    (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
     
    , Apr 29, 2004
    #1
    1. Advertising

  2. Sumit Rajan Guest

    <> wrote in message
    news:...
    > (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.
     
    Sumit Rajan, Apr 29, 2004
    #2
    1. Advertising

  3. Guest

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

    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).

    > 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?

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

    >
    >
    > 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
     
    , Apr 29, 2004
    #3
  4. Sumit Rajan Guest

    <> wrote in message
    news:...
    > > A<T>::f() or this->f()

    >
    > 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.

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

    > >
    > >
    > > 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!

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

    Regards,
    Sumit.
     
    Sumit Rajan, Apr 29, 2004
    #4
  5. >>>>int main()
    >>>>{
    >>>>B<int> b;
    >>>>b.g();
    >>>>};
    >>>
    >>>
    >>>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!
    >
    > 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!

    --
    http://www.it-is-truth.org/
     
    Asfand Yar Qazi, Apr 29, 2004
    #5
  6. Dave Moore Guest

    wrote in message news:<>...
    > (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
     
    Dave Moore, Apr 29, 2004
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fraser Ross

    using declaration and ADL

    Fraser Ross, Sep 9, 2005, in forum: C++
    Replies:
    5
    Views:
    264
    Victor Bazarov
    Sep 9, 2005
  2. Chris Johnson
    Replies:
    6
    Views:
    352
    Chris Johnson
    Jul 3, 2006
  3. cgv
    Replies:
    2
    Views:
    382
    =?ISO-8859-15?Q?Jens_M=FCller?=
    Oct 14, 2006
  4. Steven T. Hatton

    What would C++ look like without ADL?

    Steven T. Hatton, Dec 14, 2006, in forum: C++
    Replies:
    7
    Views:
    310
    F.J.K.
    Dec 14, 2006
  5. Igor R.

    ADL

    Igor R., Feb 17, 2009, in forum: C++
    Replies:
    3
    Views:
    430
    Igor R.
    Feb 18, 2009
Loading...

Share This Page