Let's suppose I have a struct like this:
struct my_struct
{
int a;
int b;
}
I have a function which should set a new value for either "a" or "b". This function also requires to specify which variable to set. A typical example would be like this:
void f(int which, my_struct* s, int new_value)
{
if(which == 0)
s->a = new_value;
else
s->b = new_value;
}
For reasons I won't write here I cannot pass the pointer to a/b to f. So I cannot call f with address of my_struct::a or my_struct::b.
Another thing I cannot do is to declare a vector (int vars[2]) within my_struct and pass an integer as index to f. Basically in f I need to access the variables by name.
Problem with previous example is that in the future I plan to add more variables to struct and in that case I shall remember to add more if statements to f, which is bad for portability.
A thing I could do is write f as a macro, like this:
#define FUNC(which)
void f(my_struct* s, int new_value) \
{ \
s->which = new_value; \
}
and then I could call FUNC(a) or FUNC(b).
This would work but I don't like using macros.
So my question is: Is there a way to achieve the same goal using templates instead of macros?
EDIT: I'll try to explain why I cannot use pointers and I need access to variable by name.
Basically the structure contains the state of a system. This systems needs to "undo" its state when requested. Undo is handled using an interface called undo_token like this:
class undo_token
{
public:
void undo(my_struct* s) = 0;
};
So I cannot pass pointers to the undo method because of polymorphism (mystruct contains variables of other types as well).
When I add a new variable to the structure I generally also add a new class, like this:
class undo_a : public undo_token
{
int new_value;
public:
undo_a(int new_value) { this->new_value = new_value; }
void undo(my_struct *s) { s->a = new_value}
};
Problem is I don't know pointer to s when I create the token, so I cannot save a pointer to s::a in the constructor (which would have solved the problem).
The class for "b" is the same, just I have to write "s->b" instead of s->a
Maybe this is a design problem: I need an undo token per variable type, not one per variable...
To answer the exact question, there is, but it's pretty complicated, and it will purely be a compile-time thing. (If you need runtime lookup, use a pointer-to-member - and based on your updated question, you may have misunderstood how they work.)
First, you need something you can use to represent the "name of a member" at compile time. In compile-time metaprogramming, everything apart from integers has to be represented by types. So you'll use a type to represent a member.
For example, a member of type integer that stores a person's age, and another for storing their last name:
struct age { typedef int value_type; };
struct last_name { typedef std::string value_type; };
Then you need something like a map that does lookup at compile time. Let's called it ctmap. Let's give it support for up to 8 members. Firstly we need a placeholder to represent the absence of a field:
struct none { struct value_type {}; };
Then we can forward-declare the shape of ctmap:
template <
class T0 = none, class T1 = none,
class T2 = none, class T3 = none,
class T4 = none, class T5 = none,
class T6 = none, class T7 = none
>
struct ctmap;
We then specialise this for the case where there are no fields:
template <>
struct ctmap<
none, none, none, none,
none, none, none, none
>
{
void operator[](const int &) {};
};
The reason for this will be come clear (possibly) in a moment. Finally, the definition for all other cases:
template <
class T0, class T1, class T2, class T3,
class T4, class T5, class T6, class T7
>
struct ctmap : public ctmap<T1, T2, T3, T4, T5, T6, T7, none>
{
typedef ctmap<T1, T2, T3, T4, T5, T6, T7, none> base_type;
using base_type::operator[];
typename T0::value_type storage;
typename T0::value_type &operator[](const T0 &c)
{ return storage; }
};
What the hell's going on here? If you put:
ctmap<last_name, age> person;
C++ will build a type for person by recursively expanding the templates, because ctmap inherits from itself, and we provide storage for the first field and then discard it when we inherit. This all comes to a sudden stop when there are no more fields, because the specialization for all-none kicks in.
So we can say:
person[last_name()] = "Smith";
person[age()] = 104;
It's like looking up in a map, but at compile time, using a field-naming class as the key.
This means we can also do this:
template <class TMember>
void print_member(ctmap<last_name, age> &person)
{
std::cout << person[TMember()] << std::endl;
}
That's a function that prints one member's value, where the member to be printed is a type parameter. So we can call it like this:
print_member<age>(person);
So yes, you can write a thing that is a little like a struct, a little like a compile-time map.
#include <iostream>
#include <ostream>
#include <string>
struct my_struct
{
int a;
std::string b;
};
template <typename TObject, typename TMember, typename TValue>
void set( TObject* object, TMember member, TValue value )
{
( *object ).*member = value;
}
class undo_token {};
template <class TValue>
class undo_member : public undo_token
{
TValue new_value_;
typedef TValue my_struct::* TMember;
TMember member_;
public:
undo_member(TMember member, TValue new_value):
new_value_( new_value ),
member_( member )
{}
void undo(my_struct *s)
{
set( s, member_, new_value_ );
}
};
int main()
{
my_struct s;
set( &s, &my_struct::a, 2 );
set( &s, &my_struct::b, "hello" );
std::cout << "s.a = " << s.a << std::endl;
std::cout << "s.b = " << s.b << std::endl;
undo_member<int> um1( &my_struct::a, 4 );
um1.undo( &s );
std::cout << "s.a = " << s.a << std::endl;
undo_member<std::string> um2( &my_struct::b, "goodbye" );
um2.undo( &s );
std::cout << "s.b = " << s.b << std::endl;
return 0;
}
In addition to Daniel Earwicker's answer, we can use variadic templates in the new C++ standard to achieve the same.
template <typename T>
struct Field {
typename T::value_type storage;
typename T::value_type &operator[](const T &c) {
return storage;
}
};
template<typename... Fields>
struct ctmap : public Field<Fields>... {
};
This code is cleaner and does not have fixed bound of members. You can use it in the same way
struct age { typedef int value_type; };
struct last_name { typedef std::string value_type; };
ctmap<last_name, age> person;
person[last_name()] = "Smith";
person[age()] = 104;
Mykola Golubyev's answer is good, but it can be improved slightly by using the fact that pointers to members can be used as non-type template parameters:
#include <iostream>
#include <ostream>
#include <string>
struct my_struct
{
int a;
std::string b;
};
template <typename TObject, typename TMember, typename TValue>
void set( TObject* object, TMember member, TValue value )
{
( *object ).*member = value;
}
class undo_token {};
template <class TValue, TValue my_struct::* Member>
class undo_member : public undo_token
{
// No longer need to store the pointer-to-member
TValue new_value_;
public:
undo_member(TValue new_value):
new_value_(new_value)
{}
void undo(my_struct *s)
{
set( s, Member, new_value_ );
}
};
int main()
{
my_struct s;
set( &s, &my_struct::a, 2 );
set( &s, &my_struct::b, "hello" );
std::cout << "s.a = " << s.a << std::endl;
std::cout << "s.b = " << s.b << std::endl;
undo_member<int, &my_struct::a> um1( 4 );
um1.undo( &s );
std::cout << "s.a = " << s.a << std::endl;
undo_member<std::string, &my_struct::b> um2( "goodbye" );
um2.undo( &s );
std::cout << "s.b = " << s.b << std::endl;
return 0;
}
This shaves off the cost of a pointer to member from each instance of undo_member.
I'm not sure why you cannot use a pointer so I don't know if this is appropriate, but have a look at C++: Pointer to class data member, which describes a way you can pass a pointer to a data member of a struct/class that does not point directly to the member, but is later bound to a struct/class pointer. (emphasis added after the poster's edit explaining why a pointer cannot be used)
This way you do not pass a pointer to the member - instead it is more like an offset within a object.
It sounds like what you're looking for is called "reflection", and yes it's often implemented with some combination of templates and macros. Be warned that reflection solutions are often messy and annoying to work with, so you may want to do some research into them before you dive into the code to find out if this is really what you want.
Second hit on Google for "C++ reflection templates" was a paper on "Reflection support by means of template metaprogramming". That should get you started. Even if it's not quite what you're looking for, it may show you a way to solve your problem.
You can't use templates to solve this, but why use a struct in te first place? This seems like an ideal use for a std::map which would map names to values.
From what you described, i am guessing you have no way of redefining the structure.
If you did, i'd suggest you use Boost.Fusion to describe your structure with template-named fields. See associative tuples for more information on that. Both kinds of structures might actually be compatible (same organization in memory), but i'm pretty sure there is no way to get such a guarantee from the standard.
If you don't, you can create a complement to the structure that would give you access to fields the same way that associative tuples do. But that can be a bit verbal.
EDIT
Now it's pretty clear that you can define the structures the way you want to. So i definitely suggest you use boost.fusion.
I can't think of a reason why you would not have everything at hand when creating an undo command. What you want to be able to undo, you have done. So i believe you can use pointers to class members and even pointers to the fields of a particular class instance when creating the undo command.
You're right in your EDIT section. It is a matter of design.
Related
Im trying to create a system capable of allocating any type, and grouping same types together in arrays.
I want to be able to retrieve each array later using so I can iterate over each type.
Something like this:
ObjectDatabase
{
template<typename T>
T* Allocate();
template<typename T>
Array<T>& GetObjects();
}
My Array type is actually a pool so allocation/deletion is fast.
I thought about mapping each Array in a std::map using an int representing the type id for each T, but then each type T would need to inherit from a base class, so it can be stored in the map, and thus leading to casting when I iterate over the array.
I think this pattern has been done before but I'm not sure how.
Can someone help?
Update:
So I'm trying to basically create a structure like this:
struct ObjectDatabase
{
Array<Entities> mEntities;
Array<Transforms> mTransforms;
Array<Physics> mPhysics;
Array<Graphics> mGraphics;
}
But I wanted to somehow create the set of arrays at compile time.. using templates?
Then provide template functions to get access to each array, and to allocate from each array
You probably want to use templates to do type elision. Here's an example that may be similar to what you're looking for. The ObjectDatabase class uses templates and polymorphism internally to do type elision so the classes used don't have any constraints on them (other than the normal constraints for being placed in a standard library container).
#include <iostream>
#include <typeinfo>
#include <deque>
#include <map>
#include <cassert>
using namespace std;
struct ObjectDatabase {
ObjectDatabase() { }
template<typename T>
T &allocate() {
deque<T> &a = getObjects<T>();
a.push_back(T());
return a.back();
}
template<typename T>
deque<T> &getObjects() {
CollectionBase *&el = m_obdb[typeid(T).name()];
if ( not el )
el = new Collection<T>();
Collection<T> *elc = dynamic_cast<Collection<T>*>(el);
assert(elc);
deque<T> &a = elc->elements;
return a;
}
~ObjectDatabase() {
for ( ObDB::iterator i=m_obdb.begin(); i!=m_obdb.end(); ++i)
delete i->second;
}
private:
ObjectDatabase(ObjectDatabase const &);
ObjectDatabase &operator=(ObjectDatabase const &);
struct CollectionBase {
virtual ~CollectionBase() { }
};
template<typename T>
struct Collection : CollectionBase {
deque<T> elements;
};
typedef map<string, CollectionBase *> ObDB;
ObDB m_obdb;
};
struct Foo {
Foo() : name("Generic Foo") { }
char const *name;
};
struct Bar {
string name;
};
int main() {
ObjectDatabase obdb;
obdb.allocate<Foo>().name = "My First Foo";
obdb.allocate<Bar>().name = "My First Bar";
{
Foo &f = obdb.allocate<Foo>();
f.name = "My Second Foo";
Bar &b = obdb.allocate<Bar>();
b.name = "My Second Bar";
}
obdb.allocate<Foo>();
obdb.allocate<Bar>();
{
cout << "Printing Foo Names\n";
deque<Foo> &foos = obdb.getObjects<Foo>();
for ( deque<Foo>::iterator i = foos.begin(); i!=foos.end(); ++i )
cout << " -> " << i->name << "\n";
}
{
cout << "Printing Bar Names\n";
deque<Bar> &bars = obdb.getObjects<Bar>();
for ( deque<Bar>::iterator i = bars.begin(); i!=bars.end(); ++i )
cout << " -> " << i->name << "\n";
}
}
When I run this program, I get this output:
Printing Foo Names
-> My First Foo
-> My Second Foo
-> Generic Foo
Printing Bar Names
-> My First Bar
-> My Second Bar
->
This shows that the individual objects are stored in containers specific to their own type. You'll notice that Foo and Bar are nothing special, just regular aggregates. (Foo would even be a POD if it weren't for its default constructor.)
======== EDIT ========
If you don't want to use RTTI, you need to get rid of the typeid and dynamic_cast.
Getting rid of the dynamic_cast is fairly simple --- you don't actually need it. You can use static_cast instead; you just can't check that the derived type is correct with the assert() anymore. (But if the type was wrong, it would be a bug anyway.)
The typeid is a bit trickier, since that is used to construct an identifier to differentiate between different concrete types. But you can use some template magic and static objects to replace the string (from type_info::name()) with a simple void const * pointer:
template<typename T>
struct TypeTag {
static char const tag;
};
template<typename T>
char const TypeTag<T>::tag = '\0';
template<typename T>
void const *get_typemarker() {
return &TypeTag<T>::tag;
}
Now we can use get_typemarker<T>() to return a void const * key into the map. We change the type of ObDB's key from string to void const * and replace typeid(T).name() with get_typemarker<T>(). I've tested it and it gives the same output in my test program as the RTTI-enabled version.
I've got a list of types which can be send over the network, take this example:
enum types {
E_T1,
E_T2,
E_T3,
E_T4
};
Now I have a list of classes which correspond to each of the types, let's say each is declared as class E_T1 {...}, class E_T2 {...}, etc.
They are not derived from a common base class and it's not possible to do so. Each of the classes has a verification method I need to invoke with the data send over the network. The client sends the data D and a id correspointing to the message type. I need to get hold of the object corresponding to the type. I can use C++0x features if needed.
What I've tried so far is using specialized templates for the types, holding a typedef for the object related to it. This was obviously a stupid idea as templates parameters need to be compile time constant so doing something along getType<data.id()>::type is not possible.
Then I tried using Boost.Variant to get a common returnable type like this (used mpl vector to iterate over the registered types at runntime for debbuging):
template <typename C>
struct getType() {
typedef C type;
}
typedef boost::mpl::vector<
getType<E_T1>,
getType<E_T2>,
getType<E_TX>...
> _types;
typedef boost::make_variant_over<_types>::type _type;
//use a map to store each type <-> id
boost::unorderd_map<types, _type> m;
m[E_T1] = getType<E_T1>();
m[data.id()]::type x; //<- access type, can now call x.validate(data)
The problem with this is that it's limited to 20 entries per variant per default. This can be overwritten but from what I understood the overhead per type should be considered and we are talking about a few thousand types here.
Also tried boost.any but it doesn't hold any type information so that's out of the question again. Has anyone any good ideas how this can be solved elegantly?
Looking for something where I don't have to write a 1k switch statement anytime I handle a type.
All types are nown at compile type, same goes for their corresponding IDs.
Id -> Type resolving needs to happen at runtime though.
Thanks in advance,
Robin.
External Polymorphism (*)
It's a widely known idiom, however it's widely used: I first encountered it in the shared_ptr implementation and it's been quite useful in my toolbox.
The idea is to actually create a base class for all those types. But not having them derive from it directly.
class Holder {
public:
virtual ~Holder() {}
virtual void verify(unsigned char const* bytes, size_t size) const = 0;
}; // class Holder
template <typename T>
class HolderT: public Holder {
public:
HolderT(): _t() {}
virtual void verify(unsigned char const* bytes, size_t size) const {
_t.verify();
}
private:
T _t;
}; // class HolderT
template <typename T>
std::unique_ptr<Holder> make_holder() {
return std::unique_ptr<Holder>(new HolderT<T>());
}
So, it's the classic strategy of adding a new level of indirection.
Now, you obviously do need a switch to move from value to class. Or perhaps... a map ?
using maker = std::unique_ptr<Holder> (&)();
using maker_map = std::unordered_map<types, maker>;
std::unique_ptr<Holder> select(types const E) {
static maker_map mm;
if (mm.empty()) {
mm.insert(std::make_pair(E_T1, make_holder<EC_T1>));
// ...
}
maker_map::const_iterator it = mm.find(E);
if (it == mm.end()) { return std::unique_ptr<Holder>(); }
return (*it->second)();
}
And now you can handle them polymorphically:
void verify(types const E, unsigned char const* bytes, size_t size) {
std::unique_ptr<Holder> holder = select(E);
if (not holder) { std::cerr << "Unknown type " << (int)E << "\n"; return; }
holder->verify(bytes, size);
}
Of course, you're welcome to make the strategy vary according to your needs. For example moving the map out of select so that you can register your types dynamically (like for plugins).
(*) At least that's the name I have for it, I would quite happy to find out it's already been named.
I'll assume you have a generic way of handling a message, such as for example an overloaded function:
void handle_message(const E_T1& msg);
void handle_message(const E_T2& msg);
//...
Now, you do not really need to get the object's type. All you need is a way to handle a message of that type, given the undecoded message.
So, I recommend you populate a map of factory functions:
std::unordered_map<types, std::function<void (unsigned char const* bytes, size_t size)> handlers;
handlers[E_E1] = [](unsigned char const* bytes, size_t size) { handle_message(E_T1(bytes, size)); };
// ...
Then, once you've decoded the type, you can use handlers[type](bytes, size) to decode and handle a message.
Try variadic templates and your already defined getType class:
enum types { T1_ID, T2_ID, .... };
class T1; class T2; class T3; ....
template <types t> struct getType;
template <> struct getType<T1_ID> { typedef T1 type; };
template <> struct getType<T2_ID> { typedef T2 type; };
...
And the operation verify:
template <types...>
struct type_operation;
template <types t1, types... rest>
struct type_operation<t1, rest...>
{
void verify(types t)
{
if (t == t1)
{
typename getType<t1>::type a;
a.verify(); // read from network and verify the rest of data....
}
else type_operation<rest...>::verify(t, data);
}
};
template <>
struct type_operation<>
{
void verify(types t)
{
ostringstream log; log << "not suppoted: " << t;
throw std::runtime_error(log.str()); //
}
};
Usage:
typedef type_operation<T1_ID, T2_ID, T3_ID, ,,.., TN_ID> type_mapping;
types id;
readFromNetwork(id);
type_mapping::verify(id);
What can I do to make this work:
template<class C, class V, Test V::*>
class Test {
};
it gives me compiler error:
unknown type name 'Test'
It's a self-referencing template for now, which doesn't seem possible. What could possibly be done to make it work?
EDIT:
Here's what I'd need this for. I want to implement a bi-directional (think parent-child) relationship schema with the least minimum coding effort.
template <class O, class T, Reference<T, O, Reference O::*> T::* opposite>
class Reference
{
T **data;
int count;
public:
Reference(): data(new T*[N]), count(0) {}
~Reference() {delete[] data;}
Reference &add(T *t) {
handleOtherSide();
return link(t);
}
// a lot of stuff to implement this
};
That's the collection class. Here's how it would be used:
class Partner
{
public:
Reference<Partner, Address, &Address::partner> addresses;
};
class Address
{
public:
Reference<Address, Partner, &Partner::addresses> partner;
};
My goal is to have everything necessary for Reference to work be supplied as template argument, so that there is no need to provide constructors for classes like Partner and Address (currently I supply the opposite member pointer as a constructor arg but this requires me to have explicit constructors for the participant classes). I would also need to pass in or calculate an "owner" pointer to the Reference class. I left this problem out here because I want to focus on the self-referencing template aspect.
The easiest way to think of this is boost::bimap. But the problem with bimap is that I don't want the enclosing bimap but just the left and right part of it. bimap is also not feasible because it would lead to one single bimap managing all associations of a specific relationship. It would possibly hold a large number of objects slowing down operations on it.
Are you looking for something like this? It's not self-referencing template, but you can specify derived class as a template type for base class and base class can call derived methods etc.:
template< typename PType, typename PDerived >
class TBase
{
//do stuff with TDerived
public:
bool foo( void )
{
return ( static_cast< PDerived* > ( this )->bar() );
}
};
template< typename PType >
class TDerived : public TBase< PType, TDerived< PType > >
{
friend class TBase< PType, TDerived< PType > > ;
//do stuff
protected:
bool bar( void )
{
return ( true );
}
};
EDIT: Once again, I'm not sure what's your final goal. Here is a solution to what I think you want, or, at least, some hint to what you might use to implement your design. The only requirement that I put is that both TAddress and TPartner have function with same name. See if that's what you need. In principle, you can make a helper class and use CRTP to access member function through a pointer, but I don't think you actually need it.
template< typename PType1, typename PType2 >
class TReference
{
public:
int mFlag;
TReference() :
mFlag( 0 )
{
}
TReference( int fFlag ) :
mFlag( fFlag )
{
std::cout << "Creating reference " << PType1::sName << " -> " << PType2::sName << "." << std::endl;
}
TReference< PType2, PType1 > AccessOpposite( void )
{
PType2 lTmp;
lTmp.Opposite();
return TReference< PType2, PType1 > ( -1 );
}
};
class TPartner;
class TAddress
{
public:
static const char* sName;
TReference< TAddress, TPartner > mRef;
void Opposite( void )
{
std::cout << sName << "::Opposite" << std::endl;
}
};
class TPartner
{
public:
static const char* sName;
TReference< TPartner, TAddress > mRef;
TReference< TAddress, TPartner > Opposite( void )
{
std::cout << sName << "::Opposite" << std::endl;
}
};
const char* TAddress::sName = "TAddress";
const char* TPartner::sName = "TPartner";
int main( void )
{
TAddress lAddress;
TPartner lPartner;
std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl;
lPartner.mRef = lAddress.mRef.AccessOpposite();
std::cout << lAddress.mRef.mFlag << " " << lPartner.mRef.mFlag << std::endl;
return ( 0 );
}
The problem is, what I want to achieve is not possible in C++, at least not with templates and the amount of code and classes I am aiming at (read: single line of code per member). It starts with the compiler needing forward declarations and fully defined types, which is making by-value members and template arguments of such impossible (in case of cyclic dependencies). Then it is not possible to have a member pointer as a template arg when the class of that member is not yet fully defined. The root cause of all this is how the compiler works: it is single pass. And there is nothing I can do about that.
The solution is to use by-reference members or an OO style base class or a boost::any style container to avoid the templates. With the latter 2 it might be possible to have by-value members.
Consider the following code:
struct I
{
SomeInternalState m_internalState;
};
struct S
{
I * m_i;
set_I (I * i)
{
m_i = i;
makeSomeChangesToTheInternalStateOfI(m_i);
}
};
struct S_1 : S { ... };
struct S_2 : S { ... };
...
struct S_n : S { ... };
It is given that an arbitrary count of instances of S_1, ... S_n may be created, and all of them will call set_I() only once.
Now, I want the instances of S_1, ... S_n to makeSomeChangesToTheInternalStateOfI() only once per instance of I per type of S_x, so that I could call set_I() from different instances of the same class S_x with the same instance of I and be sure that the internal state of I will be modified only during the first call.
The likely decision is to put some dispatch table into I, but I can't think of a sensible key for it, based solely on the type of S_x instance and not involving any hand-written "runtime type id" constants for all possible types S_1, ... S_n.
How do I do it?
EDIT:
The points that I should have stressed:
1) There may be more than one instance of I at a time, and the S_x-classes should be able to change the state of multiple instances of I, but only once per each instance. That is:
I i1, i2;
S_1 s1a, s1b;
S_2 s2a, s2b;
// all possible combinations:
s1a.changeStateOfI(i1);
s1b.changeStateOfI(i1);
s2a.changeStateOfI(i1);
s2b.changeStateOfI(i1);
s1a.changeStateOfI(i2);
s1b.changeStateOfI(i2);
s2a.changeStateOfI(i2);
s2b.changeStateOfI(i2);
In this fragment, the states of both i1 and i2 should only be changed once by S_1's method (via s1a) and once by S_2's (via s2a).
2) I suppose, reference-counting could be used to solve the problem - there's no need to know exactly, how many times the initialisation occurred, it's enough to know if it did or not.
EDIT2
I've marked n.m.'s suggestion as the answer, though my final solution differs a bit. Here it is, so that others may use it too:
struct AbstractS
{
I * m_i;
virtual void set_I (I * i) = 0;
};
template <typename self_T>
struct RegS : AbstractS
{
static std::set<I *> s_registeredContexts;
virtual void set_I (I * i)
{
m_i = i;
if (i == NULL || s_registeredContexts.count(i) > 0) return;
makeSomeChangesToTheInternalStateOfI(i);
contexts.insert(i);
}
};
template <typename self_T>
std::set<I *> InterpreterState<self_T>::s_registeredContexts;
struct S_1 : RegS<S_1> { ... };
struct S_2 : RegS<S_2> { ... };
...
struct S_n : RegS<S_n> { ... };
The difference compared to n.m.'s variant is that I've used the CRTP pattern here instead of enumerating the instantiations, the thing I wanted to avoid too.
You can use typeinfo as a key, but it's a bad idea. You should not count types in your program. Let me explain with a simple example.
Let's say you have a Vehicle type and its descendants Car, Truck and Bike. You call your function once per each of these classes. So far so good. Now you need, for a completely unrelated reason, to handle SUVs, RacingCars, GarbageTrucks, Trikes, RedCars, ReddishCars and YellowishReddishWithGreenishTintCars. Your decision on the number of times your function is going to be called should be completely orthogonal to your decision about introducing or not introducing separate classes for each of these cases.
So you need something to tag your Vehicles as distinct or similar, solely for the purpose of calling your function once per a bunch of similar objects. One way to achieve that is with a class template and a bunch of type parameters (any kind of type parameters).
class ChangerOfInternalStateOfI
{
public:
ChangerOfInternalStateOfI (I* i) {
makeSomeChangesToTheInternalStateOfI(i);
}
};
template <int n>
class S_N : public S
{
public:
S_N() {
static ChangerOfInternalStateOfI changer;
}
};
typedef S_N<1> S_1;
typedef S_N<2> S_2;
You can use enum instead of int, or a typename, doesn't really matter. The point is that all of your ChangerOfInternalStateOfI are distinct because they belong to distinct classes, and each of the constructors is going to be called once.
If the way with static data member n.m. mentioned doesn't meet the objective,
how about having a set containing types processed before in I?
As type_info itself isn't less-than-comparable, a simple wrapper
type_info_ is used in the following code.
If type-check has to be done polymorphically(through base class S),
runtime type information is needed.
So I made changeStateOfI be virtual.
#include <typeinfo>
#include <set>
using namespace std;
struct type_info_ {
type_info const *t;
type_info_( type_info const* t ) : t( t ) {}
bool operator<( type_info_ const& x ) const { return t->before( *x.t ); }
};
struct I {
set< type_info_ > types;
void f( type_info const& t, char const* s ) {
if ( types.insert( type_info_( &t ) ).second ) { puts( s ); }
}
};
struct S {
virtual void changeStateOfI( I& i, char const* s ) {
i.f( typeid( *this ), s );
}
};
struct S_1 : S {};
struct S_2 : S {};
int main() {
I i1, i2;
S_1 s1a, s1b;
S_2 s2a, s2b;
s1a.changeStateOfI(i1, "s1a i1");
s1b.changeStateOfI(i1, "s1b i1");
s2a.changeStateOfI(i1, "s2a i1");
s2b.changeStateOfI(i1, "s2b i1");
s1a.changeStateOfI(i2, "s1a i2");
s1b.changeStateOfI(i2, "s1b i2");
s2a.changeStateOfI(i2, "s2a i2");
s2b.changeStateOfI(i2, "s2b i2");
}
The above code printed s1a i1, s2a i1, s1a i2, s2a i2
in my environment.
Is it possible to have a member variable, that would be able to calculate pointer to the containing object from pointer to itself (in it's method)?
Let's have a foreign call interface wrapped in API like this:
template <typename Class, MethodId Id, typename Signature>
class MethodProxy;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodProxy<Class, Id, ReturnT ()(Arg1T) {
public:
ReturnT operator()(Class &invocant, Arg1T arg1);
};
and similarly for other numbers of arguments from 0 to N. For each class on the foreign side, one C++ class is declared with some traits and this template uses those traits (and more traits for argument types) to find and invoke the foreign method. This can be used like:
Foo foo;
MethodProxy<Foo, barId, void ()(int)> bar;
bar(foo, 5);
Now what I would like to do is define Foo in such way, that I can call like:
Foo foo;
foo.bar(5);
without repeating the signature multiple times. (obviously creating a static member and wrapping the call in a method is simple, right). Well, in fact, that's still easy:
template <typename Class, MethodId Id, typename Signature>
class MethodMember;
template <typename Class, MethodId Id, typename ReturnT, typename Arg1T>
class MethodMember<Class, Id, ReturnT ()(Arg1T) {
MethodProxy<Class, Id, Signature> method;
Class &owner;
public:
MethodMember(Class &owner) : owner(owner) {}
ReturnT operator()(Arg1T arg1) { return method(owner, arg1); }
};
That however means the object will end up containing many copies of pointer to itself. So I am looking for a way to make these instances being able to calculate the owner pointer from this and some additional template arguments.
I was thinking along the lines of
template <typename Class, size_t Offset, ...>
class Member {
Class *owner() {
return reinterpret_cast<Class *>(
reinterpret_cast<char *>(this) - Offset);
}
...
};
class Foo {
Member<Foo, offsetof(Foo, member), ...> member;
...
};
but this complains that Foo is incomplete type at the point.
Yes, I know offsetof is supposed to only work for "POD" types, but in practice for any non-virtual member, which this will be, works. I have similarly tried to pass pointer-to-(that)-member (using dummy base-class) in that argument, but that does not work either.
Note, that if this worked, it could also be used to implement C#-like properties delegating to methods of the containing class.
I know how to do the wrapper methods mentioned above with boost.preprocessor, but the argument lists would have to be specified in a weird form. I know how to write macro to generate generic wrappers via templates, but that would probably give poor diagnostics. It would also be trivial if the calls could look like foo.bar()(5). But I'd like to know whether some clever trick would be possible (plus only such clever trick would probably be usable for properties too).
Note: The member type can't be actually specialized on either member pointer to it nor it's offset, because the type must be known before that offset can be assigned. That's because the type can affect required alignment (consider explicit/parcial specialization).
Asking a question is the best way to realize the answer, so this is where I've got:
The offset can't be a template argument, because the type has to be known before the offset can be calculated. So it has to be returned by a function of the argument. Let's add a tag type (dummy struct) and either a put an overloaded function into Owner or directly into the tag. That way we can define everything we need on one place (using a macro). The following code compiles fine with gcc 4.4.5 and prints correct pointer for all members:
#include <cstddef>
#include <iostream>
using namespace std;
(just preamble to make it really compile)
template <typename Owner, typename Tag>
struct offset_aware
{
Owner *owner()
{
return reinterpret_cast<Owner *>(
reinterpret_cast<char *>(this) - Tag::offset());
}
};
This is what's needed to make the object aware of it's own offset. Property or functor or some other code can be added freely to make it useful. Now we need to declare some extra stuff along with the member itself, so let's define this macro:
#define OFFSET_AWARE(Owner, name) \
struct name ## _tag { \
static ptrdiff_t offset() { \
return offsetof(Owner, name); \
} \
}; \
offset_aware<Owner, name ## _tag> name
This defines structure as the tag and puts in a function returning the required offset. Than it defines the data member itself.
Note, that the member needs to be public as defined here, but we could easily add a 'friend' declaration for the tag support protected and private properties. Now let's use it.
struct foo
{
int x;
OFFSET_AWARE(foo, a);
OFFSET_AWARE(foo, b);
OFFSET_AWARE(foo, c);
int y;
};
Simple, isn't it?
int main()
{
foo f;
cout << "foo f = " << &f << endl
<< "f.a: owner = " << f.a.owner() << endl
<< "f.b: owner = " << f.b.owner() << endl
<< "f.c: owner = " << f.c.owner() << endl;
return 0;
}
This prints the same pointer value on all lines. C++ standard does not allow members to have 0 size, but they will only have the size of their actual content or 1 byte if they are otherwise empty compared to 4 or 8 (depending on platform) bytes for a pointer.
1) There's a gcc extension which seemed fitting:
enum{ d_y = __builtin_choose_expr(N,offsetof(X,y),0) };
But it didn't work as expected, even though manual says
"the built-in function does not evaluate the expression that was not chosen"
2) member pointers seemed interesting, eg. offsetof can be defined like this:
template< class C, class T >
int f( T C::*q ) {
return (int)&((*(C*)0).*q);
}
But I still didn't find a way to turn this into constexpr.
3) For now, here's another version:
#include <stdio.h>
#pragma pack(1)
template <class A, int x>
struct B {
int z;
void f( void ) {
printf( "x=%i\n", x );
}
};
#define STRUCT( A ) template< int N=0 > struct A {
#define CHILD( A, N, B, y ) }; template<> struct A<N> : A<N-1> \
{ B<A<N>,sizeof(A<N-1>)> y;
#define STREND };
STRUCT( A )
int x0;
int x1;
CHILD( A,1, B, y );
short x2;
CHILD( A,2, B, z );
char x3;
STREND
typedef A<2> A1;
int main( void ) {
A1 a;
a.y.f();
a.z.f();
}
For now, here's one MS-specific solution, still thinking how to make it more general
#include <stdio.h>
#define offs(s,m) (size_t)&(((s *)0)->m)
#define Child(A,B,y) \
__if_exists(X::y) { enum{ d_##y=offs(X,y) }; } \
__if_not_exists(X::y) { enum{ d_##y=0 }; } \
B<A,d_##y> y;
template <class A, int x>
struct B {
int z;
void f( void ) {
printf( "x=%i\n", x );
}
};
template< class X >
struct A {
int x0;
int x1;
Child(A,B,y);
Child(A,B,z);
};
typedef A<int> A0;
typedef A<A0> A1;
int main( void ) {
A1 a;
a.y.f();
a.z.f();
}
Assuming the calls actually need a reference to the containing object, just store the reference to the owner. Unless you have specific memory profiling evidence that it's causing a significant memory increase to store the extra references, just do it the obvious way.