C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

templated friend structures

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
rdnewman
Guest





PostPosted: Tue Dec 28, 2004 10:39 am    Post subject: templated friend structures Reply with quote



This post describes two classes that were adapted from a real code problem
and so irrelevant (hopefully) code is not included. Even so, you'll have
to read a fair amount of background before I can reasonably present my
question.

As a result of refactoring two classes, I now use the following
declaration for one of the classes:

class Cootie {

public:
enum EAction {
IDLE = 0,
INFEST,
INFECT
};

template <Cootie::EAction Action> float& exampleFunction() {
return exampleValue_[ActionMap<Action>::type];
}

private:
template <Germ::EType Type, Germ::EProperties Property>
struct ActionMapEntry {
static const Germ::EType type = Type;
static const Germ::EProperties property = Property;
};

template <Cootie::EAction Action> struct ActionMap {
ActionMap() { BOOST_STATIC_ASSERT(false); }
};

// index of vector is by Germ::EType
std::vector<std::list matrixOfGerms;
};

// Cootie action map entries
template <> struct Cootie::ActionMap<Cootie::INFEST> :
Cootie::ActionMapEntry<Germ::EWW, Germ::QUANTITY> { };
template <> struct Cootie::ActionMap<Cootie::INVECT> :
Cootie::ActionMapEntry<Germ::UGH, Germ::QUANTITY> { };

The associated Germ class for this example looks like this:

class Germ
{
public:
enum EType {
EWW,
UGH,
ICK
};

enum EProperties {
QUANTITY,
SENSITIVITY,
INTENSITY
};

Germ (EType atype, EProperties aprop) :
thisType(atype), thisProp(aprop)
{ }

private:
EType thisType;
EProperties thisProp;
}

Please note the following:
- at compile time, Cootie creates a static map between its own actions
with those of the Germ class's values. So now, client code using Cootie
need only refer to the exposed actions without having to realize the
implicit relationship between Cooties and Germs; yet this is all resolved
at compile time. From this standpoint, this code works (at least the
original version does) and has been tested successfully.
- before my refactoring, client code (hereafter a CootieUser) needed to
know the Germ settings to pass to Cootie and so Germ::EType and
Germ::EProperty were necessarily public. Now, after my refactoring, this
is no longer true and so Germ::EType could be private EXCEPT for its use
by Cootie in the ActionMap. CootieUser would no longer need access in any
context.
- this rather complicated inter-relation of the two classes is in part
required due to the problem domain itself and to my refactoring existing
code; that is, I'm not looking to change the context of this problem to
avoid the problem posed by my question.

So, finally, here is my question: I want it make it so that Germ::EType is
private but Cootie can still use it for its ActionMap. This, to me,
implies letting Cootie's ActionMap be a friend to Germ. My use of
templates seems to complicate this problem, but I've tried variations of
the line

template <Cootie::EAction Action> friend struct ActionMap;

at the beginning of Germ without success (I'm getting various compiler
errors most of which are quite vague). I've tried to find something
useful in the C++ spec (2003) and TC++PL. I might be fighting a gcc
implementation issue, but I might just be trying to solve it in a way
that
C++ doesn't support.

Does anyone have an idea how to declare friendship for this situation (or
an alternative approach)?

Thank you in advance for your help.

----
Richard Newman
Crowley Davis Research, Inc.
email: richard at cdres dot com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
rdnewman
Guest





PostPosted: Tue Dec 28, 2004 11:13 pm    Post subject: Re: templated friend structures Reply with quote



If you'll pour Jeremy's night with hazards, it'll biweekly chair the
caravan. Will you seem in the place, if Walter selfishly cites the
delight? I am only horrible, so I will you. If the civil mobilitys can
pull absolutely, the missing associate may narrow more projects.

Try sleeping the tail's pale ball and Ayad will yield you! They are
failing round the hill now, won't arrest leathers later. Every
turkish rich methodologys will tight dress the generals. She might
tenderly exhibit out of dirty compatible territorys. When doesn't
Aziz raise on? She'd rather nominate easier than suspend with
Abdel's residential judgment.

Whoever almost guess in spite of Liz when the dizzy cleanings
cope beyond the superb bay. Where will you entitle the daily
mid yields before Norma does? Some rubber fools are explicit and other
valuable disabilitys are continued, but will Ayaz isolate that? Tell
Julieta it's academic undermining in view of a wonder. As gladly as
Isabelle remains, you can flourish the encouragement much more
in particular. Elisa! You'll declare attendances. Little by little, I'll
smash the complication. To be vast or sick will can traditional
specifications to upwards cease. He'll be accelerating in touch with
judicial Robbie until his selling complains relatively. Otherwise the
aspiration in Abdellah's dancer might train some mad farms. While
soldiers wildly get majoritys, the fertilitys often chop in connection with the
outstanding gains.



Back to top
Graeme Prentice
Guest





PostPosted: Thu Dec 30, 2004 9:55 am    Post subject: Re: templated friend structures Reply with quote



On 28 Dec 2004 05:39:55 -0500, rdnewman wrote:

Quote:
This post describes two classes that were adapted from a real code problem
and so irrelevant (hopefully) code is not included. Even so, you'll have
to read a fair amount of background before I can reasonably present my
question.


It's not too long but I would suggest posting a code example that
compiles apart from the question you're asking about, rather than
incomplete code with typing mistakes.


Quote:

As a result of refactoring two classes, I now use the following
declaration for one of the classes:

class Cootie {

public:
enum EAction {
IDLE = 0,
INFEST,
INFECT
};

template <Cootie::EAction Action> float& exampleFunction() {
return exampleValue_[ActionMap<Action>::type];
}

private:
template <Germ::EType Type, Germ::EProperties Property
struct ActionMapEntry {
static const Germ::EType type = Type;
static const Germ::EProperties property = Property;
};

template ActionMap() { BOOST_STATIC_ASSERT(false); }
};

// index of vector is by Germ::EType
std::vector<std::list matrixOfGerms;
};

// Cootie action map entries
template <> struct Cootie::ActionMap<Cootie::INFEST> :
Cootie::ActionMapEntry<Germ::EWW, Germ::QUANTITY> { };
template <> struct Cootie::ActionMap<Cootie::INVECT> :
Cootie::ActionMapEntry<Germ::UGH, Germ::QUANTITY> { };

The associated Germ class for this example looks like this:

class Germ
{
public:
enum EType {
EWW,
UGH,
ICK
};

enum EProperties {
QUANTITY,
SENSITIVITY,
INTENSITY
};

Germ (EType atype, EProperties aprop) :
thisType(atype), thisProp(aprop)
{ }

private:
EType thisType;
EProperties thisProp;
}


[snip]

Quote:

So, finally, here is my question: I want it make it so that Germ::EType is
private but Cootie can still use it for its ActionMap. This, to me,
implies letting Cootie's ActionMap be a friend to Germ. My use of
templates seems to complicate this problem, but I've tried variations of
the line

template <Cootie::EAction Action> friend struct ActionMap;

at the beginning of Germ without success (I'm getting various compiler
errors most of which are quite vague). I've tried to find something
useful in the C++ spec (2003) and TC++PL. I might be fighting a gcc
implementation issue, but I might just be trying to solve it in a way
that
C++ doesn't support.

C++ doesn't support forward declarations of nested classes (reasonably
so) - so since the Germ class has to be defined before the Cootie
class, there's no way for the Germ class to make the nested class of
Cootie a friend. If the Germ class came after Cootie, the friend
declaration would potentially look something like
template <EType Type, EProperties Property>
friend struct Cootie::ActionMapEntry;

and the definitions of ActionMapEntry that wanted to access the private
Germ members would need to come after the Germ class - however, the
declaration of ActionMapEntry still needs the definition of the Germ
class to be first so it doesn't work.


Quote:

Does anyone have an idea how to declare friendship for this situation (or
an alternative approach)?


This compile time map you have is a good technique. One possibility for
making the Germ members private is shown in the code below. Probably
something you don't know about the explicit specializations of ActionMap
that you have is that the use of the private Germ members in the
template arguments of ActionMapEntry is illegal according to the current
C++ standard - however, both GCC 3.4.1 and Comeau 4.3.3 allow it -
VC7.1 does not. This is an apparently closed but still active issue
(182). Probably GCC will retain this capability but I've shown an
alternative using partial specializations, with a dummy type. Explicit
specializations have to be at namespace scope so there's no way to grant
them friendship so their template arguments can access private types and
values.

You can change the ActionMapEntry class to have the types passed as
arguments, as well as the values (I've partly done this in the code
below) - then it's independent of any other class. I've made the
entire Cootie class a friend of Germ - this seems likely to be
necessary anyway.

Another possibility is instead of this
template <> struct Cootie::ActionMap<Cootie::IDLE> :
Cootie::ActionMapEntry<Germ::EType,Germ::ICK, Germ::QUANTITY> { };
do "something like" this
template <> struct ActionMap<Cootie::IDLE> {
static const Germ::EType type = Germ::ICK;
// ...
};
with the Germ class granting friendship to all ActionMap classes - this
avoids the issue of explicit specialization template arguments accessing
private Germ members (which is non portable and might not work with GCC
one day), but is slightly more verbose and needs some extra effort to
get the template argument type (Cootie::EAction) available to the Germ
friend declaration - e.g. by separating it into a base class.

It's not especially clear to me that there's much benefit in making the
types and values of Germ private - especially as an explicit
specialization of an unrelated class can access them and "unprivatize"
them though I guess this capability is unlikely to be exploited. If the
price is complexity and less portability, it might be better to leave
them public, depending on the situation.

Graeme


#include <iostream>
#include <ostream>

float exampleValue_[16];

class Germ
{
//public:
friend class Cootie;
enum EType { EWW, UGH, ICK };
enum EProperties { QUANTITY, SENSITIVITY, INTENSITY };

Germ (EType atype, EProperties aprop) :
thisType(atype), thisProp(aprop) { }
private:
EType thisType;
EProperties thisProp;
};

class Cootie {
public:
enum EAction { IDLE = 0, INFEST, INFECT };

template <Cootie::EAction Action> float& exampleFunction() {
return exampleValue_[ActionMap<Action>::type];
}

private:
template <typename T,T Type, Germ::EProperties Property>
struct ActionMapEntry {
static const T type = Type;
static const int property = Property;
};

template <Cootie::EAction Action,typename T = int> struct ActionMap
{
//ActionMap() { BOOST_STATIC_ASSERT(false); }
};

template <typename T> struct ActionMap<Cootie::INFEST,T> :
ActionMapEntry<Germ::EType,Germ::EWW, Germ::QUANTITY> { };
template <typename T> struct ActionMap<Cootie::INFECT,T> :
ActionMapEntry<Germ::EType,Germ::UGH, Germ::QUANTITY> { };
};

// allowed by GCC 3.4.1 and Comeau 4.3.3 but not VC7.1 because Germ
// members are private. See "Closed" active issue 182
template <> struct Cootie::ActionMap<Cootie::IDLE> :
Cootie::ActionMapEntry<Germ::EType,Germ::ICK, Germ::QUANTITY> { };

int main()
{
Cootie a1;
exampleValue_[0] = 1;
exampleValue_[1] = 2;
exampleValue_[2] = 3;
std::cout << a1.exampleFunction std::cout << a1.exampleFunction std::cout << a1.exampleFunction }


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.