tags:

views:

276

answers:

4

Simplified version of the code:

Foo.h:

class Foo {
    private:
        class Bar {
            // ...
        };
        typedef std::map<int, Bar> mapType;
        mapType _map;
    public:
        void method(mapType::iterator it);
};

Foo.cpp:

void Foo::method(mapType::iterator it) {
    // ...
    notMethod(it);
}

void notMethod(mapType::iterator it) {
    // ...
}

Unsurprisingly, I get the error 'mapType' is not a class or namespace name in VS2008 at notMethod's definition. Is there any (elegant) way that I can avoid having to type out std::map<int, Bar> everywere in notMethod's definition without turning notMethod into a method?

+23  A: 

Use

void notMethod(Foo::mapType::iterator it) {
    // ...
}

and put the typedef in the public section of Foo's class declaration.

Edit:

If you want to avoid this, you can

  1. make notMethod a friend (as suggested by DanDan),
  2. use sbi's template solution, or
  3. make notMethod a private static member function of Foo (which generates exactly the same code as if it was a free non-member function).

Which solution is the most appropriate really depends on what notMethod does.

If notMethod uses Bar and Bar really only makes sense in the context of Foo's internal implementation, I would make notMethod a private static member function, since it's part of Foo's internals.

If notMethod was an operator that needs to take a non-Foo as its first argument (meaning that it can't be a member of Foo), and if I wanted to keep Bar private, I would make the operator a friend.

If notMethod implements a generic operation on iterators, I would make it a template function.

If Bar is a class that might be of interest to Foo's clients, I would make Bar and the typedef public and use the solution I suggested originally.

Martin B
Yup, this works... doesn't the public typedef expose class Bar to some degree though?
suszterpatt
That's correct. I'll edit the answer to discuss what your alternatives are to making the typedef public.
Martin B
@suszterpatt: If you truly want any non-method (such as `notMethod()`) to be able to take this iterator parameter, then logically you *should* expose the typedef (and thus `Bar`). If you don't want "any old" non-method to be able to take such a parameter, then use one of Martin's other alternatives. As one more alternative, you could make all `Bar`'s members private and declare `Foo` to be a friend of `Bar`.
j_random_hacker
+4  A: 

Friends.

Add

friend void notMethod(mapType::iterator it);

to your Foo class and you can keep your inner classes and functions private.

DanDan
Don't you think that declaring something as friend in this case is an overkill?
Paolo Tedesco
No. It is better than making the internal private class public.
DanDan
This doesn't work as you posted it originally, but changing `mapType` to `Foo::mapType` everywhere in `notMethod` is all you need to get it working. :)Also, @orsogufo: why do you think a friend function is overkill?
suszterpatt
Sorry, I had really misunderstood the question :( Please ignore my previous comment...
Paolo Tedesco
+5  A: 

Building upon Martin B's answer:

The reason notMethod doesnt know the type mapType is because it is inside the class Foo, you can think of classes as namespaces in this case if you want.

Either way, you must change the code to:

void notMethod(Foo::mapType::iterator it) {}

If you agree with Martin B, you must move the typedef to the public section of the class. If you agree with DanDan you must Friend the function.

Myself? I would put the typedef outside the class, and put both the class and the typedef into a namespace.

mizipzor
From what I can tell, `notMethod()` is not inside the class `Foo`.
sbi
Correct, it is not. However, the typedef mapType is. Compare the placement of Foo:: in method() and (in the corrected) notMethod().
mizipzor
+3  A: 

Martin B has provided you with an answer. Here's an alternative:

Your notMethod() looks like some implementation detail to me, that's likely defined in the cpp file's unnamed namespace. What I usually do in this case is to make notMethod() a template:

template< typename It >
void notMethod(It it) {
    // ...
}

Besides avoiding to make the typedef public or making the function a friend, this has the added benefit that, should the function provide a useful algorithm, you can invoke it with other iterators, too.

sbi
Interesting trick, I'll have to remember this. :)
suszterpatt