Issue with friendship in a separate namespace

Hey guys, I'm having problems declaring a friend function in a separate namespace.

Here's a simplified example of what I'm trying to do;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

namespace ns
{
    class Class  // Class exists in a separate namespace
    {
    private:
        Class() {}

        friend Class* Friend();  // I want Friend to be a friend
    };
}

typedef ns::Class Type;  // typedef it to Type

inline Type* Friend()
{
    return new Type;  // but this fails because Friend isn't a friend
}

int main()
{
    Friend();
    return 0;
}


Qualifying Friend as being in the global namespace works. IE:
 
friend Class* ::Friend; // <- :: to indicate global namespace 


However, this solution requires Friend be prototyped before Class is defined. This is not an option because Friend's prototype depends on the Type typedef which can't exist until after the class is defined.

Somewhat oddly, the above works fine if I remove the namespace completely. I wouldn't have thought that namespace makes any difference, but I guess it's making ns::Friend a friend and not ::Friend.


Can this be done? I have an alternative approach I can take if not, but I'd like to get this working if possible.

Thanks!
Disch wrote:
This is not an option because Friend's prototype depends on
the Type typedef which can't exist until after the class is defined.

Is there a reason you can't make Friend a template?
It wouldn't really make sense to make it a template. It should only exist for Type.

And doing that would make it more difficult to call. (Friend<Type>() vs. Friend())


EDIT: I guess I could get a little more into what I'm doing.

'Class' is going to be different (often platform specific) implementations of the same idea. The Classes themselves will be buried behind some #ifdefs, as will the appropriate 'Type' typedef.

Friend will be the same, regardless of which Class is used, so I don't want to have to repeat it for each one.
Last edited on
Disch wrote:
Friend will be the same, regardless of which Class is
used, so I don't want to have to repeat it for each one.

Is repeating only Friend's declaration acceptable?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>

#define CLASS_VERSION 1

#if CLASS_VERSION == 1

namespace ns { class Class_1; }

ns::Class_1 * Friend();

#elif CLASS_VERSION == 2

namespace ns { class Class_2; }

ns::Class_2 * Friend();

#endif

#if CLASS_VERSION == 1

namespace ns
{
    class Class_1
    {
    private:
        Class_1() {}

        friend Class_1 * ::Friend();
    };
}

typedef ns::Class_1 Type;

#elif CLASS_VERSION == 2

namespace ns
{
    class Class_2
    {
    private:
        Class_2() {}

        friend Class_2 * ::Friend();
    };
}

typedef ns::Class_2 Type;

#endif

inline Type * Friend()
{
    std::cout
        << "CLASS_VERSION == "
        << CLASS_VERSION
        << std::endl;

    return new Type;
}

int main()
{
    delete Friend();
    return 0;
}

EDIT: I guess it's not if Friend's definition really is just
one line and you have many different class versions...
Last edited on
Ok, that's the best I can do.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <boost/preprocessor/tuple.hpp>
#include <boost/preprocessor/stringize.hpp>

#define TOTAL_CLASSES 6

#define CURRENT_CLASS 3

#define CLASS_NAMES (Class_A, Class_B, Class_C, Class_D, Class_E, Class_F)

#define CURRENT_CLASS_NAME \
    BOOST_PP_TUPLE_ELEM(TOTAL_CLASSES, CURRENT_CLASS, CLASS_NAMES)

namespace ns { class CURRENT_CLASS_NAME; }

ns::CURRENT_CLASS_NAME * Friend();

#include <iostream>

int main()
{
    std::cout << BOOST_PP_STRINGIZE(CURRENT_CLASS_NAME) << std::endl;

    return 0;
}
Class_D

Maybe someone else has a better idea.
closed account (z05DSL3A)
Disch wrote:
EDIT: I guess I could get a little more into what I'm doing.

'Class' is going to be different (often platform specific) implementations of the same idea. The Classes themselves will be buried behind some #ifdefs, as will the appropriate 'Type' typedef.

Friend will be the same, regardless of which Class is used, so I don't want to have to repeat it for each one.


Abstract factory pattern?
closed account (DSLq5Di1)
Disch wrote:
However, this solution requires Friend be prototyped before Class is defined. This is not an option because Friend's prototype depends on the Type typedef which can't exist until after the class is defined.
Why not foward declare the class too?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace ns
{
    class Class; // forward declaration
}
typedef ns::Class Type;  // typedef it to Type

Type* Friend(); // forward declaration

namespace ns
{
    class Class
    {
    private:
        Class() {};
        friend Class* ::Friend();
    };
}

inline Type* Friend()
{
    return new Type;
}
Grey Wolf wrote:
Abstract factory pattern?

The typical abstract factory design pattern is useful when the choice of
the type of the  object  to create is made while the  program  executes.

I believe Disch picks a class during compilation and sticks with it the
whole time. Also, I believe he doesn't have the option to make that
choice while the program executes, because then he would have to
actually compile code for all his target platforms while he (obviously)
builds his  project  on one of them, and that would not be  possible.
Therefore, he is doomed to use #ifdefs, whether he wants it or not.

I guess he could use the boost preprocessor library to somehow implement
a compile - time abstract factory  pattern,  though. That would be very neat.

sloppy9 wrote:
Why not foward declare the class too?

That was the main idea in my previous posts.

@Disch:

I have some more questions. 

Why is it bad to put  Friend  inside  the  namespace?  And
why is it bad to even make it a static function of the class?
Last edited on
closed account (DSLq5Di1)
@m4ster r0shi
Aye, I can see that now.. I skimmed over your post before replying sorry, it looked overly verbose. ^^
closed account (z05DSL3A)
m4ster r0shi,

The Abstract Factory Pattern is not limited to a runtime choice, the Concrete Factory can be chosen at compile time.

Not a very good example but...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>

class IWidget
{
public:
    virtual void draw() = 0;
};

class ThisWidget : public IWidget
{
public:
    void draw() { std::cout << "ThisWidget\n"; }
};

class ThatWidget : public IWidget
{
public:
    void draw() { std::cout << "ThatWidget\n"; }
};

class IFactory
{
public:
   virtual IWidget* create() = 0;
};

class ThisFactory: public IFactory
{
    IWidget* create() {return new ThisWidget;}
};

class ThatFactory: public IFactory
{
    IWidget* create() {return new ThatWidget;}
};


#ifdef THIS_FACTORY
IFactory* factory = new ThisFactory;
#else
IFactory* factory = new ThatFactory;
#endif


int main()
{
    IWidget* widget = factory->create();

    widget->draw();

    return 0;
}
Thanks for the input everyone. I don't have time to really examine and consider everything now, but I'll pop back in after work today.

I appreciate it!
See http://www.ideone.com/gIeig . It works fine there.
Grey Wolf wrote:
The Abstract Factory Pattern is not limited to a runtime
choice, the Concrete Factory can be chosen at compile time.

Fair enough.

Though, this is not the real problem here (and I was wrong to say that it was). The real
problem is that you have to  compile  both classes. What if, let's say, in the one you use
pthreads and in the other  windows  threads? My point is that you can't limit the  #ifdef
directives just to the  point  of the  creation  of your  objects.  Also, if you can make that
choice during compilation without the  dynamic  polymorphism  overhead, why not do it?
Last edited on
closed account (z05DSL3A)
The real problem is that you have to  compile  both classes.
Why?

What if, let's say, in the one you use pthreads and in the other  windows  threads?
you do a conditional compile with your build system.

Also, if you can make that choice during compilation without the  dynamic  polymorphism  overhead, why not do it?
Go for it, I merely made a suggestion.
Last edited on
Grey Wolf wrote:
you do a conditional compile with your build system

Yes, that's what  I'm  saying.  This means that I have to put
more #ifdef directives.The whole idea of a factory is to keep
this kind of checks only  around  the point of object creation.

Grey Wolf wrote:
Go for it

Okay. This is what I have in mind:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/tuple.hpp>

#include <iostream>
#include <cstdlib>

#define TOTAL_BUILDS  2
#define CURRENT_BUILD 0

#define CONSOLE_NAMES (WindowsConsole, LinuxConsole)

#define CLS_FUNCTION_0 system("cls");
#define CLS_FUNCTION_1 system("clear");

#define CLS_FUNCTIONS (CLS_FUNCTION_0, CLS_FUNCTION_1)

#define CURRENT_CONSOLE_NAME \
    BOOST_PP_TUPLE_ELEM(TOTAL_BUILDS, CURRENT_BUILD, CONSOLE_NAMES)

#define CURRENT_CLS_FUNCTION \
    BOOST_PP_TUPLE_ELEM(TOTAL_BUILDS, CURRENT_BUILD, CLS_FUNCTIONS)

class CURRENT_CONSOLE_NAME
{
public:

    static void Clear() { CURRENT_CLS_FUNCTION }
};

typedef CURRENT_CONSOLE_NAME Console;

int main()
{
    std::cout << "Using " << BOOST_PP_STRINGIZE(CURRENT_CONSOLE_NAME);

    std::cout << " (hit enter)"; std::cin.get();

    Console::Clear();

    std::cout << "Hello, world! (hit enter)"; std::cin.get();

    Console::Clear();

    std::cout << "Hello, again! (hit enter)"; std::cin.get();

    return 0;
}
Using WindowsConsole (hit enter)
(I hit enter. Console clears.)
Hello, world! (hit enter)
(I hit enter. Console clears.)
Hello, again! (hit enter)
(I hit enter. Program terminates.)
Last edited on
closed account (z05DSL3A)
m4ster r0shi wrote:
This means that I have to put more #ifdef directives.
I give up, I really don't care...


P.S. Go for it was an answer to your question not a request for you to do anything.
Grey Wolf wrote:
I give up

\(^o^)/

Grey Wolf wrote:
Go for it was an answer to your question not a request for you to do anything.

I know.
xD
Grey Wolf:

Your IWidget example looks similar to what I have as my fallback if I can't get something similar to the OP working. The second example seems less practical if the classes in question are nontrivial.

My fallback was this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
namespace ns
{
    class Class
    {
    public:
        static Class* Func()
        {
            return new Class;
        }
    private:
        Class() {}

    };
}

typedef ns::Class Type;

inline Type* Friend()
{
    return new Type::Func();
}

int main()
{
    Friend();
    return 0;
}


However this solution is not ideal. There are two things I want to improve upon:

1) I don't want anything like 'Func' exposed to the user. I only want the user to use 'Friend'
2) This requires a duplicate (and practically identical) implementation for Func in every version of Class.


The solutions here don't seem to address those two points without introducing more implementation-specific code. Grey Wolf's latest example, for instance, would require a new Class implementation to modify a handful of different macros.

One detail I failed to mention earlier (I might have made my example too simplistic in my efforts to keep the problem simple =x). Class derives from a known Parent. And all functions available in Class with be virtual (implementing Parent's functions).

With that in mind, I'm now thinking of making an intermediary class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Intermediate : public Parent
{
private:
    static Intermediate* Func();
    friend Intermediate* Friend();
};

namespace ns
{
    class Class : public Intermediate
    {
    };
}

typedef ns::Class Type;  // typedef it to Type

inline Intermediate* Friend()
{
    return Intermediate::Func();
}

inline Intermediate* Intermediate::Func()
{
    return new Type;
}

int main()
{
    Friend();
    return 0;
}


I think this should fit the bill well enough, even if it's a little more round-about then I'd like.

Thanks for all the input everyone. Grey Wolf in particular, your factory idea got me thinking about this in a new way. I appreciate it.
Oh, I see now...

I didn't know what a build system is -> http://en.wikipedia.org/wiki/GNU_build_system

I should have thought that something like that was possible.
After all, the GoF themselves mention in their book that...
ET++ uses the Abstract Factory pattern to achieve portability across
different window systems (X Windows and SunView, for example).

I apologise to Grey Wolf for my being so strongly opinionated...
Last edited on
Topic archived. No new replies allowed.