syntax error in std::vector<T>::const_iterator where T = (class) U<V>

Discussion in 'C++' started by m0shbear, Feb 6, 2011.

  1. m0shbear

    m0shbear Guest

    With the following code, I get the following error from my compiler:
    "In member function 'void B<U>::C()': error: expected ';' before 'x'".
    Which subtlety of using templates am I not aware of?

    #include <vector>
    template <class T> struct A {};
    template <class U> struct B {
    void C() { std::vector<A<U> >::const_iterator x;}
    };
    int main(){}
    m0shbear, Feb 6, 2011
    #1
    1. Advertising

  2. m0shbear

    Bo Persson Guest

    m0shbear wrote:
    > With the following code, I get the following error from my compiler:
    > "In member function 'void B<U>::C()': error: expected ';' before
    > 'x'". Which subtlety of using templates am I not aware of?
    >
    > #include <vector>
    > template <class T> struct A {};
    > template <class U> struct B {
    > void C() { std::vector<A<U> >::const_iterator x;}
    > };
    > int main(){}


    That the compiler cannot formally know that
    std::vector<A<U>>::const_iterator is a type (because someone could
    specialize std::vector for some user defined types). You have to add a
    'typename' to specify what it is:

    void C() { typename std::vector<A<U> >::const_iterator x;}


    Bo Persson
    Bo Persson, Feb 6, 2011
    #2
    1. Advertising

  3. m0shbear

    m0shbear Guest

    On Feb 6, 3:54 am, "Bo Persson" <> wrote:
    > m0shbear wrote:
    > > With the following code, I get the following error from my compiler:
    > > "In member function 'void B<U>::C()': error: expected ';' before
    > > 'x'". Which subtlety of using templates am I not aware of?

    >
    > > #include <vector>
    > > template <class T> struct A {};
    > > template <class U> struct B {
    > > void C() { std::vector<A<U> >::const_iterator x;}
    > > };
    > > int main(){}

    >
    > That the compiler cannot formally know that
    > std::vector<A<U>>::const_iterator is a type (because someone could
    > specialize std::vector for some user defined types). You have to add a
    > 'typename' to specify what it is:
    >
    >  void C() { typename std::vector<A<U> >::const_iterator x;}
    >
    > Bo Persson


    Ah, now I understand the point of typename for disambiguating types. I
    need to start reading TC++PL more religiously. In its listing of
    vector, it had "typedef _typename_ ..." for a reason. And now I
    understand what it is.

    I'm curious as to why it's not in the C++ FAQ yet.
    m0shbear, Feb 6, 2011
    #3
  4. Bo Persson <> wrote:
    > That the compiler cannot formally know that
    > std::vector<A<U>>::const_iterator is a type (because someone could
    > specialize std::vector for some user defined types). You have to add a
    > 'typename' to specify what it is:


    Is there any conrete example where the same dependent name could be
    used as both a type name and a non-type name, and this could potentially
    cause confusion? Why exactly is the 'typename' keyword necessary?
    Juha Nieminen, Feb 7, 2011
    #4
  5. m0shbear wrote:

    > With the following code, I get the following error from my compiler:
    > "In member function 'void B<U>::C()': error: expected ';' before 'x'".
    > Which subtlety of using templates am I not aware of?
    >
    > #include <vector>
    > template <class T> struct A {};
    > template <class U> struct B {
    > void C() { std::vector<A<U> >::const_iterator x;}
    > };
    > int main(){}


    For the typename FAQ see http://stackoverflow.com/questions/610245/where-to-
    put-the-template-and-typename-on-dependent-names
    Johannes Schaub (litb), Feb 7, 2011
    #5
  6. m0shbear

    Bo Persson Guest

    Juha Nieminen wrote:
    > Bo Persson <> wrote:
    >> That the compiler cannot formally know that
    >> std::vector<A<U>>::const_iterator is a type (because someone could
    >> specialize std::vector for some user defined types). You have to
    >> add a 'typename' to specify what it is:

    >
    > Is there any conrete example where the same dependent name could be
    > used as both a type name and a non-type name, and this could
    > potentially cause confusion? Why exactly is the 'typename' keyword
    > necessary?


    Yes, if you specialize a class there is no requirements that the base
    template and the specialization should have anything in common (except
    their names :).


    template<class T>
    class vec
    {
    public:
    class const_iterator
    {
    public:
    // some members here
    };
    };

    template<>
    class vec<int>
    {
    public:
    double const_iterator; // silly, but possible
    };


    Now, what is vec<T>::const_iterator, a type or a member variable?
    Depends on what T is!


    Bo Persson
    Bo Persson, Feb 7, 2011
    #6
  7. m0shbear

    James Kanze Guest

    On Feb 7, 5:12 pm, Juha Nieminen <> wrote:
    > Bo Persson <> wrote:
    > > That the compiler cannot formally know that
    > > std::vector<A<U>>::const_iterator is a type (because someone could
    > > specialize std::vector for some user defined types). You have to add a
    > > 'typename' to specify what it is:


    > Is there any conrete example where the same dependent name could be
    > used as both a type name and a non-type name, and this could potentially
    > cause confusion? Why exactly is the 'typename' keyword necessary?


    extern int p;
    template<typename T>
    struct S : B<T>
    {
    B<T>::x * p; // marked statement
    };

    If B<T>::x is the name of a type, the marked statement is a
    declaration of a pointer to that type. If it is the name of a
    constant or a variable, the marked statement is an expression
    statement, and the * is multiplication.

    In a lot of cases, context would allow the compiler to make it
    clear: only a type is legal, or a type is not legal, but the
    committee decided to not require the compiler to take any
    context into consideration.

    --
    James Kanze
    James Kanze, Feb 8, 2011
    #7
  8. Bo Persson <> wrote:
    > Juha Nieminen wrote:
    >> Bo Persson <> wrote:
    >>> That the compiler cannot formally know that
    >>> std::vector<A<U>>::const_iterator is a type (because someone could
    >>> specialize std::vector for some user defined types). You have to
    >>> add a 'typename' to specify what it is:

    >>
    >> Is there any conrete example where the same dependent name could be
    >> used as both a type name and a non-type name, and this could
    >> potentially cause confusion? Why exactly is the 'typename' keyword
    >> necessary?

    >
    > Yes, if you specialize a class there is no requirements that the base
    > template and the specialization should have anything in common (except
    > their names :).


    In your example if you try to use the specialization in code where
    'const_iterator' is expected to be a type, you get a syntax error. In
    the exact same way as if that 'typename' keyword had been specified.
    So what's the difference?

    That's not what I asked. I asked if there's a situation where you *don't*
    get a syntax error, but it compiles fine but causes unwanted behavior.
    Juha Nieminen, Feb 8, 2011
    #8
  9. James Kanze <> wrote:
    > In a lot of cases, context would allow the compiler to make it
    > clear: only a type is legal, or a type is not legal, but the
    > committee decided to not require the compiler to take any
    > context into consideration.


    The following doesn't compile. Why shouldn't it? I see no rational
    reason why the compiler should refuse to compile it.

    //---------------------------------------------------------------
    #include <iostream>

    template<typename T>
    void foo()
    {
    T::f(); // Is 'f' a function or a type?
    }

    struct A
    {
    // 'f' is a function
    static void f() { std::cout << "A\n"; }
    };

    struct B
    {
    // 'f' is a type
    struct f
    {
    f() { std::cout << "B\n"; }
    };
    };

    int main()
    {
    foo<A>();
    foo<B>(); // Fails because B::f is a type
    }
    //---------------------------------------------------------------
    Juha Nieminen, Feb 8, 2011
    #9
  10. m0shbear

    Paul Guest

    "Juha Nieminen" <> wrote in message
    news:4d50e156$0$2819$...
    > James Kanze <> wrote:
    >> In a lot of cases, context would allow the compiler to make it
    >> clear: only a type is legal, or a type is not legal, but the
    >> committee decided to not require the compiler to take any
    >> context into consideration.

    >
    > The following doesn't compile. Why shouldn't it? I see no rational
    > reason why the compiler should refuse to compile it.
    >
    > //---------------------------------------------------------------
    > #include <iostream>
    >
    > template<typename T>
    > void foo()
    > {
    > T::f(); // Is 'f' a function or a type?
    > }
    >
    > struct A
    > {
    > // 'f' is a function
    > static void f() { std::cout << "A\n"; }
    > };
    >
    > struct B
    > {
    > // 'f' is a type
    > struct f
    > {
    > f() { std::cout << "B\n"; }


    Where is this function declared?

    > };
    > };
    >
    > int main()
    > {
    > foo<A>();
    > foo<B>(); // Fails because B::f is a type
    > }
    > //---------------------------------------------------------------
    >
    Paul, Feb 8, 2011
    #10
  11. m0shbear

    James Kanze Guest

    On Feb 8, 6:23 am, Juha Nieminen <> wrote:
    > James Kanze <> wrote:
    > > In a lot of cases, context would allow the compiler to make it
    > > clear: only a type is legal, or a type is not legal, but the
    > > committee decided to not require the compiler to take any
    > > context into consideration.


    > The following doesn't compile. Why shouldn't it? I see no rational
    > reason why the compiler should refuse to compile it.


    Because the standard says that it shouldn't compile:). You've
    presented an interesting question, however...

    > //---------------------------------------------------------------
    > #include <iostream>
    >
    > template<typename T>
    > void foo()
    > {
    > T::f(); // Is 'f' a function or a type?


    What's interesting here is that the syntax is remarkably similar
    in both cases. Formally, if f is a function, this line is
    a function call; if it's a type, the line is an "explicit type
    conversion (funtional notation)". But unlike a lot of the other
    cases, it's easy to imagine an implementation which doesn't
    really distinguish between the two until far later. The choice,
    here, can't have any impact on later code.

    Still, the standard says that when parsing the template, the
    compiler is required to assume that f is not a type.

    > }


    > struct A
    > {
    > // 'f' is a function
    > static void f() { std::cout << "A\n"; }
    > };


    > struct B
    > {
    > // 'f' is a type
    > struct f
    > {
    > f() { std::cout << "B\n"; }
    > };
    > };


    > int main()
    > {
    > foo<A>();
    > foo<B>(); // Fails because B::f is a type}
    > //---------------------------------------------------------------


    That's what the standard requires.

    I don't see why the compiler couldn't defer the decision in this
    case; I suppose that the only reason it doesn't is to be
    orthogonal with cases where it must know.

    --
    James Kanze
    James Kanze, Feb 8, 2011
    #11
  12. m0shbear

    Paul Guest

    "James Kanze" <> wrote in message
    news:...
    > On Feb 8, 6:23 am, Juha Nieminen <> wrote:
    >> James Kanze <> wrote:
    >> > In a lot of cases, context would allow the compiler to make it
    >> > clear: only a type is legal, or a type is not legal, but the
    >> > committee decided to not require the compiler to take any
    >> > context into consideration.

    >
    >> The following doesn't compile. Why shouldn't it? I see no rational
    >> reason why the compiler should refuse to compile it.

    >
    > Because the standard says that it shouldn't compile:). You've
    > presented an interesting question, however...
    >
    >> //---------------------------------------------------------------
    >> #include <iostream>
    >>
    >> template<typename T>
    >> void foo()
    >> {
    >> T::f(); // Is 'f' a function or a type?

    >
    > What's interesting here is that the syntax is remarkably similar
    > in both cases. Formally, if f is a function, this line is
    > a function call; if it's a type, the line is an "explicit type
    > conversion (funtional notation)". But unlike a lot of the other
    > cases, it's easy to imagine an implementation which doesn't
    > really distinguish between the two until far later. The choice,
    > here, can't have any impact on later code.
    >
    > Still, the standard says that when parsing the template, the
    > compiler is required to assume that f is not a type.
    >
    >> }

    >
    >> struct A
    >> {
    >> // 'f' is a function
    >> static void f() { std::cout << "A\n"; }
    >> };

    >
    >> struct B
    >> {
    >> // 'f' is a type
    >> struct f
    >> {
    >> f() { std::cout << "B\n"; }
    >> };
    >> };

    >
    >> int main()
    >> {
    >> foo<A>();
    >> foo<B>(); // Fails because B::f is a type}
    >> //---------------------------------------------------------------

    >
    > That's what the standard requires.
    >
    > I don't see why the compiler couldn't defer the decision in this
    > case; I suppose that the only reason it doesn't is to be
    > orthogonal with cases where it must know.
    >
    > --


    This doesn't happen on my compiler. MS 32-bit optimising compiler version
    14.00......
    Here is my source code:

    #include <iostream>
    struct A{static void bar(){std::cout<<"A function.";}
    };
    struct B{
    struct bar{ bar(){std::cout<<"In constructor.";} };
    };

    template<typename T>void foo() { T::bar();}

    int main(){
    foo<B>();
    foo<A>();
    }

    // Output = In constructor.A function.
    Paul, Feb 8, 2011
    #12
  13. Re: syntax error in std::vector<T>::const_iterator where T = (class)U<V>

    On 02/08/2011 07:23 AM, Juha Nieminen wrote:
    > James Kanze<> wrote:
    >> In a lot of cases, context would allow the compiler to make it
    >> clear: only a type is legal, or a type is not legal, but the
    >> committee decided to not require the compiler to take any
    >> context into consideration.

    >
    > The following doesn't compile. Why shouldn't it? I see no rational
    > reason why the compiler should refuse to compile it.
    >
    > //---------------------------------------------------------------
    > #include<iostream>
    >
    > template<typename T>
    > void foo()
    > {
    > T::f(); // Is 'f' a function or a type?
    > }
    >


    If T::f(); were a function, it would have to return something (either
    void, or a pointer, reference or object of some type). Since the class
    name is "foo", it can't be parsed as a constructor. So it shouldn't
    compile in any case, even lacking the "typename" keyword.

    If you had written "T::foo();" instead, no typename would be needed
    since this would obviously be the declaration of a class constructor (at
    least I don't think it could be interpreted any other way).
    Robert Hairgrove, Feb 8, 2011
    #13
  14. Re: syntax error in std::vector<T>::const_iterator where T = (class)U<V>

    On 02/08/2011 06:31 PM, Robert Hairgrove wrote:

    >> template<typename T>
    >> void foo()
    >> {
    >> T::f(); // Is 'f' a function or a type?
    >> }
    >>

    >
    > If T::f(); were a function, it would have to return something (either
    > void, or a pointer, reference or object of some type). Since the class
    > name is "foo", it can't be parsed as a constructor. So it shouldn't
    > compile in any case, even lacking the "typename" keyword.


    Oops ... I overlooked the fact that this is a function template, not a
    class template.

    So the compiler should look for a member function of T called f()
    returning void. 'f' could not be a type (nor could T::f).
    Robert Hairgrove, Feb 8, 2011
    #14
  15. m0shbear

    Bo Persson Guest

    Juha Nieminen wrote:
    > Bo Persson <> wrote:
    >> Juha Nieminen wrote:
    >>> Bo Persson <> wrote:
    >>>> That the compiler cannot formally know that
    >>>> std::vector<A<U>>::const_iterator is a type (because someone
    >>>> could specialize std::vector for some user defined types). You
    >>>> have to add a 'typename' to specify what it is:
    >>>
    >>> Is there any conrete example where the same dependent name could
    >>> be used as both a type name and a non-type name, and this could
    >>> potentially cause confusion? Why exactly is the 'typename' keyword
    >>> necessary?

    >>
    >> Yes, if you specialize a class there is no requirements that the
    >> base template and the specialization should have anything in
    >> common (except their names :).

    >
    > In your example if you try to use the specialization in code where
    > 'const_iterator' is expected to be a type, you get a syntax error.
    > In
    > the exact same way as if that 'typename' keyword had been specified.
    > So what's the difference?


    The difference is that the compiler should be allowed to diagnose
    template code before it is instantiated. If you don't know whether a
    name is a type or not, a lot of code turns out to be impossible to
    interpret. For example, is "a * b" a pointer declaration or a
    multiplication? If I use b later on in the class, am I then using this
    pointer or some b from an outer scope?

    >
    > That's not what I asked. I asked if there's a situation where you
    > *don't* get a syntax error, but it compiles fine but causes
    > unwanted behavior.


    It isn't allowed to do that. A name must either be a type or not. If
    the compiler can't tell, it must assume that it is not.


    Bo Persson
    Bo Persson, Feb 8, 2011
    #15
  16. m0shbear

    James Kanze Guest

    On Feb 8, 12:38 pm, "Paul" <> wrote:
    > "James Kanze" <> wrote in message


    > news:...


    [...]
    > >> struct A
    > >> {
    > >> // 'f' is a function
    > >> static void f() { std::cout << "A\n"; }
    > >> };


    > >> struct B
    > >> {
    > >> // 'f' is a type
    > >> struct f
    > >> {
    > >> f() { std::cout << "B\n"; }
    > >> };
    > >> };


    > >> int main()
    > >> {
    > >> foo<A>();
    > >> foo<B>(); // Fails because B::f is a type}
    > >> //---------------------------------------------------------------


    > > That's what the standard requires.


    > > I don't see why the compiler couldn't defer the decision in this
    > > case; I suppose that the only reason it doesn't is to be
    > > orthogonal with cases where it must know.


    > This doesn't happen on my compiler. MS 32-bit optimising compiler version
    > 14.00......


    Not all compilers are up to date concerning this. A lot
    (included VC++ through 2005, at least) continue to defer all
    template parsing until instantiation, at which point in time,
    the meaning of f is unambiguously known. Implementing the
    latest rules for name lookup in templates (aka breaking existing
    code) isn't always the highest priority of compiler writers.

    --
    James Kanze
    James Kanze, Feb 9, 2011
    #16
  17. Paul <> wrote:
    >> struct B
    >> {
    >> // 'f' is a type
    >> struct f
    >> {
    >> f() { std::cout << "B\n"; }

    >
    > Where is this function declared?


    It's a constructor.
    Juha Nieminen, Feb 10, 2011
    #17
  18. m0shbear

    Paul Guest

    "Juha Nieminen" <> wrote in message
    news:4d5423b7$0$2853$...
    > Paul <> wrote:
    >>> struct B
    >>> {
    >>> // 'f' is a type
    >>> struct f
    >>> {
    >>> f() { std::cout << "B\n"; }

    >>
    >> Where is this function declared?

    >
    > It's a constructor.
    >

    My bad, I misread it. No problem I seen it after I posted.
    Paul, Feb 10, 2011
    #18
    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. Anonymous
    Replies:
    20
    Views:
    4,271
    Pete Becker
    Mar 30, 2005
  2. Jason Heyes
    Replies:
    8
    Views:
    707
    Andrew Koenig
    Jan 15, 2006
  3. Replies:
    8
    Views:
    1,890
    Csaba
    Feb 18, 2006
  4. Markus Dehmann
    Replies:
    2
    Views:
    621
    Abhishek Padmanabh
    Jun 8, 2008
  5. Rune Allnor
    Replies:
    4
    Views:
    923
    Rune Allnor
    Dec 11, 2008
Loading...

Share This Page