0

I ran across some C++ code recently that typedefed a struct in a parent class. However, it seemed to be unavailable in the child class, even tho it was not marked private (it was protected). I've created a minimal working example (below) below that demonstrates this failure. I have turned everything public and it still fails. The error that is given is (using g++):

B.h:8: error: expected ',' or '...' before '&' token
B.h.8: error: ISO C++ forbids declartion of 'Datum' with no type

A.h (compiles)

template<typename S, typename T> class A {
public:
    typedef struct {
        S x;
        T y;
    } Datum;
};

B.h (does not compile)

#include "A.h"
template<typename Q> class B : public A<Q, Q> {
public:
    void output(const Datum& dat);
};

B.h (compiles)

#include "A.h"
template<typename Q> class B : public A<Q, Q> {
public:
    typedef struct {
        Q x;
        Q y;
    } Datum;
    void output(const Datum& dat);
};

Why does the first version of B.h not compile? Is the second one a safe alternative? Is there a better (more concise or idiomatic) way to handle this?

curiousguy
  • 8,038
  • 2
  • 40
  • 58
Keith Pinson
  • 7,835
  • 7
  • 61
  • 104
  • I'm confident that `A.h` does *not* compile as written. – Kerrek SB Aug 15 '12 at 17:21
  • @KerrekSB Thank you. I am in a situation where I cannot copy and paste, so I made an error in it. Fixed now. – Keith Pinson Aug 15 '12 at 17:26
  • possible duplicate of [Propagating 'typedef' from based to derived class for 'template'](http://stackoverflow.com/questions/1643035/propagating-typedef-from-based-to-derived-class-for-template) – Bo Persson Aug 15 '12 at 18:01
  • @BoPersson the answers turn out to be related, but I would say the question is not duplicate because if I had known how closely related that question was, I probably would have known my solution already. I.e. I'd say the answers are similar but the questions are different. – Keith Pinson Aug 15 '12 at 18:13
  • @Kazark - That's a matter of opinion. :-) There are lots of questions about why names from templated base classes are not visible - all for the same reason. The linked to question has the `typedef` in common with this, but the problem is general. – Bo Persson Aug 15 '12 at 18:17
  • @Kazark Because your question is not gcc-specific, I have removed this tag. And I have added [tag:name-lookup] also. – curiousguy Aug 16 '12 at 03:05
  • @BoPersson Do we need a dependent-base-class tag? – curiousguy Aug 16 '12 at 03:15
  • Same underlying issue: [In a templated derived class, why do I need to qualify base class member names with “this->” inside a member function?](http://stackoverflow.com/questions/7908248/in-a-templated-derived-class-why-do-i-need-to-qualify-base-class-member-names-w/7908530#7908530) – curiousguy Aug 16 '12 at 03:50

2 Answers2

2

You need to say typename A<Q,Q>::Datum inside B. Since the base is a template, its names are dependent names and not visible during the first phase, and you need typename to specify that the name names a type (and not a value or a template).

You should also lose the typedef. C++ works differently from C, and you should say:

struct Datum { S x; T y };
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
1

This

typedef struct {
    S x;
    T y;
}

is ill-formed. typedef needs a type and an "alias" to name that type. What you probably need is

template<typename S, typename T> 
class A {
 public:
    struct Datum { S x; T y; };
};

without the typedef, which is not necessary at all here. Then, you need to qualify the Datum name properly, as typename A<Q,Q>::Datum:

#include "A.h"
template<typename Q> 
class B : public A<Q, Q> {
 public:
    void output(const typename A<Q,Q>::Datum& dat);
};
juanchopanza
  • 223,364
  • 34
  • 402
  • 480