Alan Johnson wrote:

>
>>How about a global function, perhaps contained in the same

namespace your classes are in.

Yes it works. But is it "the right place"?

Absolutely.

If you want some authoritative word on that try Item 23 of Scott Meyer's

Effective C++: "Prefer non-member non-friend functions to member

functions."

I do not know what Scott Meyer meant, but think, it is not general rule.

Member function can have encapsulated data so member function can be better

than plain function.

OP note, that the function "distance" can be shared between several classes,

else more than one copy of code must be at least maintained.

With "copy of code" in fact we are speaking about implementation of the

function "distance". So we need to have one implementation of the function

for all possible declarations of the function, in other words we need

abstract function declaration (interface) to be separated from the function

implementation.

In our case we have interface completely separated from its implementation.

In general case we can have only part of implementation of the interface

shared between several interfaces.

Let we will make the shared implementation as plain function. The plane

function (even placed into own namespace) does not allow us

- to use inheritance as design way to make new improved version of the plain

function,

- to have runtime template with the help of virtual function,

- to hide some data with the function

- and so on.

There are two design patterns existing to help to implement similar

separations: "bridge" and "strategy". The "strategy" can be useful design

pattern in our case.

Also free-standing class with inline members can be good solution instead of

"plane function placed into own namespace". There are no overhead here.

You also can declare inline member function in each class (if you want) to

compare with other class and make forward to its implementation. Consider

the following example:

-- cut here --

namespace Ndecl

{

class type{};

//

template<class First, class Second>

class Dist_implementation

{

public:

inline type distance( const First&, const Second& );

inline type distance( const Second&, const First& );

};

//

template<class First, class Second>

inline type distance( const First& f, const Second& s )

{

Dist_implementation<First,Second di;

di.distance(f,s);

}

template<class First, class Second>

inline type distance( const Second& s, const First& f )

{

Dist_implementation<First,Second di;

di.distance(s,f);

}

//namespace Ndecl

}

/*

//*******************************

-= C++ limitation =-

"define" does not exist as template parameter,

so can not do like this:

//declaration

template<define Dist_implementation>

class GeometricObject

{

protected:

template<class First, class Second>

type distance(const Second& obj)

{

//with "define" we avoid here

//"Dist_implementation is not template" problem

Dist_implementation<First,Second di;

return

di.distance

(

static_cast<const First&>(*this),

obj

);

}

};

//inheritance

template<define Dist_implementation>

class Segment:

public GeometricObject<Dist_implementation>

{

typedef GeometricObject<Dist_implementationTparent;

using Tparent::distance;

public:

template<class Second>

type distance(const Second& obj)

{

return

//-= probably g++ limitation =- : Tparent::distance<Segment,Second>

static_cast<Tparent&>(*this).template

distance<Segment,Second>

(

obj

);

}

};

//instantiating

Segment<Ndecl::Dist_implementation seg;

//implementation Ndecl::Dist_implementation

-=C++ limitation=-

can not point to itself in template parameter like this

template<>type

Dist_implementation<

class Segment<Dist_implementation>,

class Arc<Dist_implementation>

>::

distance(

const Segment<Dist_implementation>&,

const Arc<Dist_implementation>&

)

{

}

so we are forced to use other namespace and

inherit only to make link to itself

namespace Nimpl

{

using Ndecl::Dist_implementation;

class GeometricObject:

public Ndecl::GeometricObject

<

Ndecl::Dist_implementation

>

{

....

};

class Segment:

public Ndecl::Segment

<

Ndecl::Dist_implementation

>

{

....

};

class Arc:

public Ndecl::Arc

<

Ndecl::Dist_implementation

>

{

....

};

//namespace Nimpl

}

// *******************************************

so in order to separate "Dist_implementation" and

"GeometricObject" we must use other namespace and

"using" directive or must use "#define" directive

of preprocessor

*/

namespace Ndecl2

{

using Ndecl::Dist_implementation;

using Ndecl::type;

//

class GeometricObject

{

//can not declare here and it is correct

//Dist_implementation di;

protected:

template<class First, class Second>

type distance(const Second& obj)

{

//can be worse than global data due to ctor/dtor calls

Dist_implementation<First,Second di;

return

di.distance(

static_cast<const First&>(*this),

obj

);

}

};

// ***

//

class Segment:

public GeometricObject

{

public:

template<class Second>

type distance(const Second& obj)

{

return

GeometricObject::distance<Segment,Second>

(

obj

);

}

};

//

class Arc:

public GeometricObject

{

public:

template<class Second>

type distance(const Second& obj)

{

return

GeometricObject::distance<Arc,Second>

(

obj

);

}

};

//namespace Ndecl2

}

//specialization

namespace Ndecl

{

using Ndecl2::Arc;

using Ndecl2::Segment;

//

template<>type

Dist_implementation<Arc,Segment>::

distance

(

const Arc&,

const Segment&

)

{

//your "distance" for Arc& and Segment& here

return type();

}

//

template<>type

Dist_implementation<Arc,Segment>::

distance

(

const Segment& s,

const Arc& a

)

{

return distance(a,s);

}

/*

-=C++ limitation=-

can not declare comutative template parameters like this

template<>

class Dist_implementation<Segment,Arc>

is alias Dist_implementation<Arc,Segment>;

It is maybe correct, I think C++ must not have complicated

template design stuff integrated to itself, but C++ must

have only integrated bidirectional bridge to the external

stuffs like this.

It is due to the possible integrated design stuff can turn C++

into "langauge of exceptions from self rules", but

simultaneosly the integrated stuff always will be limited

by ordinary C++ syntax and that is why can be unsuitable

for concrete application domain.

*/

template<>

class Dist_implementation<Segment,Arc>

{

Dist_implementation<Arc,Segment di;

public:

type distance( const Segment& s, const Arc& a )

{

return di.distance(s,a);

}

type distance( const Arc& a, const Segment& s )

{

return di.distance(a,s);

}

};

//namespace Ndecl

}

// *********************************************

//

int main()

{

using namespace Ndecl2;

Segment seg;

Arc arc;

//the following are equal

seg.distance<Arc>(arc);

arc.distance<Segment>(seg);

Ndecl::Dist_implementation<Arc,Segment di;

di.distance(arc,seg);

Ndecl::distance<Arc,Segment>(arc,seg);

}

-- cut here --

--

Maksim A. Polyanin

http://grizlyk1.narod.ru/cpp_new
"In thi world of fairy tales rolls are liked olso"

/Gnume/