0

I'm writing a btree implementation class 'btree' inside a file btree.h and implemented inside btree.tem with an external iterator class 'btree_iterator' in a file btree_iterator.h implemented in a file btree_iterator.tem

Here is the (stripped down) content of btree.h:

#include "btree_iterator.h"

template <typename T> class btree 
{
 public:

  friend class btree_iterator<T>;
  typedef btree_iterator<T> iterator;

  iterator find(const T& elem);
};

#include "btree.tem"

Now in implementing the find function, I have the following stub implementation in btree.tem:

template <typename T> iterator btree<T>::find(const T& elem) //LINE 24
{
    return NULL;
}

(I've only included lines of code that are relevant to my question)

When I compile I get the following errors:

btree.tem:24: error: expected constructor, destructor, or type conversion before 'btree'

Now I know that this has something to do with the fact that I've declared the typedef for iterator inside the class declaration and is therefore scoped only inside that block. But I've tried to put another line of typedef in btree.tem but it just won't work.

How should it be written?

Arvin
  • 1,391
  • 4
  • 19
  • 33

4 Answers4

3

Write this:

template <typename T>
typename btree<T>::iterator btree<T>::find(const T& elem) //LINE 24
{
  //;;
}

Since iterator is a nested type, you've to write btree<T>::iterator, and since it is a dependent nested type as it depends on the template argument type T, you've to use typename as well:

  typename btree<T>::iterator
//^^^^^^^^ must use it as iterator is a dependent type!

See a detailed explanation here:

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • Why do you keep editing your grammatical mistakes back in? :( – Lightness Races in Orbit Oct 13 '11 at 17:30
  • Thanks for that! I didn't know you had to use typename again, but it makes sense – Arvin Oct 13 '11 at 17:31
  • @TomalakGeret'kal: Because `"you've"` is not a grammatical mistake. – Nawaz Oct 13 '11 at 17:32
  • @Nawaz: If you don't like them, why do you keep editing them back in? Let me help you, friend. :) – Lightness Races in Orbit Oct 13 '11 at 17:33
  • @TomalakGeret'kal: I edited my previous comment. I didn't know you edited my post, and you were referring to that. – Nawaz Oct 13 '11 at 17:35
  • @Nawaz: `'ve` is practically pretty close to a grammatical mistake in the contexts above, because in colloquial English we would _never_ use it like that. It's weird. [edit: a cursory glance at Google suggests it's an Indian phenomenon.] – Lightness Races in Orbit Oct 13 '11 at 17:35
  • Thankfully the English language is much more flexible than C++ ;) – Arvin Oct 13 '11 at 17:36
  • @Arvin: Not if you have OCD! And, if you don't, you have no business programming :) – Lightness Races in Orbit Oct 13 '11 at 17:36
  • 1
    @Nawaz : "You've" is fine in certain contexts, but "you've to" is not one of them. – ildjarn Oct 13 '11 at 17:36
  • @TomalakGeret'kal: But we use it all the time. I never heard anyone saying it's error. – Nawaz Oct 13 '11 at 17:36
  • @Nawaz: Define "we"; I've never heard it other than from you, and I'd gawk at it if heard, as would everyone I know. When "have to" is introducing an imperative, you want to hear "have" for the emphasis. ("You _have_ to do this.") Off the top of my head, it only feels natural when part of the bastardisation "have got" (e.g. "you've got three minutes"), or when otherwise introducing a past participle (e.g. "you've passed me the wrong fork, honey"). – Lightness Races in Orbit Oct 13 '11 at 17:39
3

Your return type is broken (there's no iterator in global scope!), and you're going to need to qualify the dependent type with typename:

template <typename T>
typename btree<T>::iterator btree<T>::find(const T& elem)
{
    return NULL;
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
1

iterator is a nested type within btree<T>. When you define the function you are outside the scope of the class so you need to qualify the type as typename btree<T>::iterator.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • I've changed the function definition to template btree::iterator btree::find(const T& elem) {// stuff} however it still gives me the same error? – Arvin Oct 13 '11 at 17:28
  • 1
    @Arvin: `iterator` is a dependent type so it still needs `typename` in there. I've just edited my answer. – K-ballo Oct 13 '11 at 17:29
  • *when you define the function you are outside of the scope of the class*: Only for the return type, lookup for the arguments will be performed inside the class scope. – David Rodríguez - dribeas Oct 13 '11 at 17:52
1

The lookup scopes in a member function definition are slightly asymmetric. Lookup for the return type is performed in the enclosing scope while arguments are looked up in the class scope. This means that while for the arguments you can use the unqualified name of the typedef, you cannot do that for the return type. For an ilustrative example:

struct test {
   typedef int integer;
   integer f( integer x );
};
// [1]                   [2]
test::integer test::f( integer x ) {
   return x;
}

The return type [1] is in the enclosing namespace scope, and in that scope integer is not defined, so you need to qualify it. On the other hand, arguments to the member function are looked up inside the class scope, so you can use the unqualified integer there.

In your particular case, because you are using a template you have the added complexity of having to add the typename before the dependent name. But the important part of the problem is that lookup for the return type is performed in the enclosing scope.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489