homogenous containers, derived classes, initializer lists and move semantics - c++

I have code that makes use of some dirty tricks to make it appear as what I believe is a nice interface. The most important class, Worker, is designed to make the caller construct it with temporaries; the constructor will then take them. I think the code is self-explanatory:
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
struct Base
{
virtual void
print
( void )
{
cout << "Base" << endl;
};
};
struct Derived1 : public Base
{
virtual void
print
( void )
{
cout << "Derived1" << endl;
};
};
struct Derived2 : public Base
{
virtual void
print
( void )
{
cout << "Derived2" << endl;
};
};
class Worker
{
private:
/* Arrays can't hold references, and
* vectors are homogenous, so the
* only option is to use (smart) pointers. */
vector< unique_ptr<Base> >
V
;
/* The dirty trick I spoke about. */
template<typename T> void
init
( T && t )
{
V.emplace_back( new T( forward<T>(t) ) );
return;
};
template<typename T , typename ... U> void
init
( T && t , U && ... u )
{
V.emplace_back( new T( forward<T>(t) ) );
/* The usage of std::move() is explained below. */
init(move(u)...);
return;
};
public:
template<typename ... T>
Worker
( T && ... t )
{
/* Use std::move() because, inside the body
* of the function, the arguments are lvalues.
* If I hadn't put std::move(), the compiler
* would complain about an attempt of using
* _new_ with a reference type (above). */
init(move(t)...);
return;
};
void
work
( void )
{
for ( const auto & x : V )
x->print();
return;
};
};
int
main
( void )
{
/* The goal: be able to create an instance of Worker
* passing temporaries to the constructor. No initializer_list
* is involved, no copies are made; clean, fast moves. */
Worker worker{ Derived1() , Base() , Derived2() };
/* This should print "Derived1\nBase\nDerived2\n". */
worker.work();
return 0;
}
Even though it compiles fine (g++ 4.8.1) and works out of the box, I feel this is not the best way to achieve my goals, and I'd like to get rid of that annoying feeling. Has anyone found another workaround for this? Are there any better aproaches, any disadvantages with my design?
Thanks in advance. The code should compile just fine, and show how I'd like my interface to be designed and why I've made use of those "tricks". Best regards,
Kalrish

Though I still think this question better belongs to Code Review, here's an alternative version for your "dirty trick"
template < typename T >
int emplace_back(T&& t)
{
V.emplace_back( std::forward<T>(t) );
return 0;
}
template<typename ... T>
Worker
( T && ... t )
{
auto i = {emplace_back(new T{forward<T>(t)})...};
};
Or, if you want to get rid of that member function:
public:
template<typename ... T>
Worker
( T && ... t )
{
using up = std::unique_ptr<Base>;
auto f = [&](up&& p)
{ V.emplace_back(std::move(p)); return 0; };
auto i = {f( up{new T{forward<T>(t)}} )...};
};
You might get a warning because i is unused, though. This variable is only required to build an initializer-list, where a pack-expansion is allowed.
Normally, I'd suggest using an initializer-list instead of the variadic template ctor (that's what they're made for), but they don't support moving out the elements as they don't own their storage.
The same problem occurs if you want to initialize the vector in the mem-initializer-list of the ctor (via pack expansion like in the alternative above).

Related

How to use different member variable names in a template?

Edit: Completely rewrote the question to address suggestions in comments
In a large project that I participate in, there are a lot of classes that wrap messages, events, etc. They do not have a common ancestor and were (and still are) written by different people in different groups.
Most of these classes (or structs) have public members indicating error codes and descriptions. However, since they are used mostly within a single group and conventions are pretty loose, some of them name the members errStr, while others use errDesc.
For example:
struct X {
// stuff here...
int errCode;
std::string errStr;
};
struct Y {
// stuff here...
int errCode;
std::string errDesc;
};
I am trying to write a function template that will accept an object and print out the value of the whatever member variable that it has.
In pseudocode:
template<typename T>
bool logError(T const& x)
{
if (x.errCode == 0)
return true;
// if (T::errStr exists)
// log(x.errStr);
// else if (T::errDesc exists)
// log(x.errDesc);
return false;
}
What complicates matters is that the compiler that we use is VS2012, which is not fully C++11 compliant.
I have been messing with std::enable_if, std::is_same, etc for a while and so far the only result is an impressive collection of different compiler errors.
I was pointed to this by #T.C.
While it turned out to work quite well, it appears clunky and I was wondering if it can be simplified, or another solution offered, using the C++11 features that VS2012 supports.
Thank you!
In principle you can use SFINAE to detect the relevant member, but with C++03 (your compiler's standard) this yields complex, verbose code that's easy to break by maintenance – I give a complete example at the end below. The relevant techniques are covered in umpteen places on the web. E.g. I googled "c++ detect data member SFINAE" and hey presto, some GitHub code, and other examples. The ability to find information on the web, including basic googling, is very important to a developer. So, just try it.
An IMO more practical approach – because it's much simpler code that does not introduce maintenance problems and that goes in the direction you want the code to evolve – is to simply define overloads of an accessor function, one per class, like this:
string errorMessageOf( X const& o ) { return o.errStr; }
string errorMessageOf( Y const& o ) { return o.errDsc; }
Not everything needs to be a template.
Ordinary overloads are nice.
Your desired function template is then
template< class Type >
bool logError( Type const& x )
{
if (x.errCode == 0) return true; // A really dangerous thing to do
// Especially in Windows error code 0 a.k.a. NOERROR etc. is
// sometimes returned by GetLastError for a genuine failure. You
// should better treat it as "unknown cause".
clog << errorMessageOf( x ) << endl;
return not clog.fail(); // The return value is unspecified.
}
Example of instead using C++03 SFINAE, with code that works with Visual C++ 2012, and supporting an arbitrary number of names for the error message data member:
#include <iostream>
#include <stddef.h>
#include <string>
//----------------------------------------------- Machinery:
namespace reusable {
typedef ptrdiff_t Size;
template< Size n >
struct SizeCarrier_ { char nPlusOne[n + 1]; };
template< class Type, Type >
struct TypeFrom_;
} // namespace reusable
namespace my{
using std::string;
namespace impl {
using reusable::SizeCarrier_;
using reusable::TypeFrom_;
struct ErrorMsgMemberId { enum Enum{ noSuch, errStrName, errDescName }; };
template< class Type >
class ErrorMsgMemberId_
{
private:
template< class U >
static SizeCarrier_< ErrorMsgMemberId::errStrName >
memberId( TypeFrom_<string U::*, &U::errStr>* );
template< class U >
static SizeCarrier_<ErrorMsgMemberId::errDescName>
memberId( TypeFrom_<string U::*, &U::errDesc>* );
template< class U >
static SizeCarrier_<ErrorMsgMemberId::noSuch>
memberId( ... );
public:
static ErrorMsgMemberId::Enum const value = static_cast<ErrorMsgMemberId::Enum>(
sizeof( memberId< Type >( 0 ).nPlusOne ) - 1
);
};
template< ErrorMsgMemberId::Enum kind >
struct ErrorMsgFunc_;
template<>
struct ErrorMsgFunc_< ErrorMsgMemberId::errStrName >
{
template< class Type >
string operator()( Type const& o ) const
{ return o.errStr; }
};
template<>
struct ErrorMsgFunc_< ErrorMsgMemberId::errDescName >
{
template< class Type >
string operator()( Type const& o ) const
{ return o.errDesc; }
};
} // namespace impl
template< class Type >
string errorMsgOf( Type const& o )
{
static impl::ErrorMsgMemberId::Enum const member_id =
impl::ErrorMsgMemberId_< Type >::value;
return impl::ErrorMsgFunc_< member_id >()( o );
}
} // namespace my
//----------------------------------------------- Example usage:
struct X {
// stuff here...
int errCode;
std::string errStr;
};
struct Y {
// stuff here...
int errCode;
std::string errDesc;
};
struct Z {
// stuff here...
int errCode;
};
int main()
{
X const x = { 1, "X::errStr" };
Y const y = { 2, "Y::errDesc" };
Z const z = { 3 };
using namespace std;
cout << my::errorMsgOf( x ) << endl;
cout << my::errorMsgOf( y ) << endl;
//cout << my::errorMsgOf( z ) << endl; //! Fails with 'noSuch' in message.
}

How to use a pointer to a generic template class to access a member function that depends on the template parameter type

Is there a way to have a pointer to a generic template class and call a function whose return value depends on the template parameter? Here's what I'm trying to do:
class Node{...}
template < typename Type > class NumberNode : public Node
{
public:
NumberNode( Type value ) : _value( value ) { }
Type getValue() { return _value; }
private:
Type _value;
}
void foo( int x ) { /* do something */ }
void foo( float x ) { /* do something else */ }
void main(...)
{
std::vector< Node* > nodes;
nodes.push_back( new NumberNode< int >( 1 ) );
nodes.push_back( new NumberNode< float >( 1.f ) );
for( Node* ptr_node : nodes )
{
foo( static_cast< NumberNode* >( ptr_node )->getValue() );
}
}
I can't do this because the static_cast( Derived* ) should know the full template type, which varies. I can't have Base be a template type either, for other classes also derive from it. Does anyone know of a workaround?
This is the right thing to do:
class Node
{
public:
virtual void foo() = 0;
};
Your loop becomes
for( Node* ptr_node : nodes )
{
ptr_node->foo();
}
foo can be implemented in NumberNode like this:
template <typename Type>
void NumberNode::foo()
{
::foo(_value);
}
Perhaps getValue() is no longer needed with this design and you can get rid of it. It's a good thing. Getters are manifestations of a weak design. Objects should do stuff, not have stuff.
If you don't want to have foo in Node for some reason (perhaps you have too many functions like foo and don't want to pollute the interface), the alternative approach is to implement the VISITOR pattern for Node. However Visitor has its own downsides, so I would only recommend using it as a last resort in this case.

Self-referencing Template in Template Argument

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.

Smart pointers as class members for polymorphism

I'm new to smart pointers and I would be really grateful if somebody could give me a hint whether the way I'm handling smart pointers as class members is correct.
More precisely, the solution that I would like to achieve is in the context of class polymorphism and should be ideally exception-safe.
Given a container of heterogeneuous objects (std::vector<shared_ptr<CBase> > my_vector), the usual way to add elements is: my_vector.push_back( shared_ptr<CBase>(new CChild(1))), so that later on, one can call the member function of the specific derived class by doing: my_vector[0]->doSomething().
What I would like to achieve is to add stack objects to the vector and still being able to do polymorphism. Intuitively sth. like: CChild<float> obj1(1); my_vector.push_back(obj1). To solve that, I'm using now the Virtual Constructor Idiom: CChild obj1(1); my_vector.push_back(obj1.clone());.
Note that in some of my derived classes, I've static member functions that create objects, e.g: CChild<float> obj1 = CChild<float>::initType2(1);
Because of requirement issues and also to have a clean interface, I've now a new class CFoo<T> that has as data member a smart pointer to the CBase<T> class. The idea is that besides containing other new private members,
this class encapsulates/handles the smart pointers to the derived objects, such that I'm allowed to do sth. like: CFoo<float> myfoo(CChild<float>::initType2(1)); my_vector.push_back(myfoo);. This means that the container is now of type vector<CFoo<T> > instead of type vector<shared_ptr<CBase> >
It's in this context, that I would like to know how to implement the constructors for a class with smart pointers as class members? What about the implementation of the operator = following the copy-swap idiom? Below, I give some ilustrations of my class design:
template < typename T >
class CBase{
public:
CBase(){};
virtual ~CBase(){};
...
virtual CBase<T> * clone() const = 0;
virtual CBase<T> * create() const = 0;
};
template < typename T >
class CChild1 : public CBase{
public:
...
CChild1<T> * clone() const { return new CChild1<T>(*this); }
CChild1<T> * create() const { return new CChild1<T>(); }
static CChild1 initType1(double, double);
static CChild1 initType2(int);
};
template < typename T >
struct type{
typedef std::tr1::shared_ptr<T> shared_ptr;
};
template < typename T >
class CFoo{
public:
CFoo();
CFoo( const CBase<T> &, int = 0 );
CFoo( const CFoo<T> & );
void setBasePtr( const CBase<T> & );
void swap( CFoo<T> & );
CFoo<T> & operator = ( CFoo<T> );
...
~CFoo();
private:
typename type<CBase<T> >::shared_ptr m_ptrBase;
int m_nParam;
};
template < typename T >
CFoo<T>::CFoo()
:m_nParam(0)
// How shall I handle here the "m_ptrBase" class member? e.g point it to NULL?
{
}
template < typename T >
CFoo<T>::CFoo(const CBase<T> & refBase, int nParam)
:m_ptrBase(refBase.clone()), // Is this initialization exception-safe?
m_nParam(nParam)
{
}
template < typename T >
CFoo<T>::CFoo(const CFoo<T> & refFoo)
:m_ptrBase(refFoo.m_ptrBase),
m_nParam(refFoo.m_nParam)
{
}
template < typename T >
void CFoo<T>::setBasePtr( const CBase<T> & refBase ){
// ??? I would like to do sth. like: m_ptrBase(refBase.clone())
}
template < typename T >
CFoo<T>::~CFoo(){
// The memory is going to be freed by the smart pointer itself and therefore
// the destructor is empty, right?
}
template < typename T >
void CFoo<T>::swap( CFoo<T> & refFoo ){
//does this here makes sense?
using std::swap;
swap(m_ptrBase, refFoo.m_ptrBase);
swap(m_nParam, refFoo.m_nParam);
}
template < typename T >
CFoo<T> & CFoo<T>::operator = ( CFoo<T> copyFoo ){
copyFoo.swap(*this);
return (*this);
}
Below an example on what I would like to intuitively achieve. First, I fill the container with CFoo<float> objects that contain smart pointers to derived classes, besides another integer class member (Note that all this is only illustrative).
std::vector<CFoo<float> > my_bank;
for (int b=0; b < 3; b++){
float x = b*sqrt(2);
my_bank.push_back( new CFoo<float>( CChild1<float>::initType2(x), b) );
}
for (double s= 1.0; s<= 8.0; s *= 2.0){
my_bank.push_back( new CFoo<float>( CChild2<float>::initType2(x), 0) );
}
Once, the container is filled, I would like to do some operations, calling to virtual functions, e.g. doSomething that are specialized in each derived class.
for (int i=0; i < (int)my_bank.size(); i++){
int b = my_bank[i].m_nParam;
CBase<float>* myChild = my_bank[i].m_ptrBase;
myChild->doSomething( param1, param2, param3, ..., b);
}
I really don't know how to approach this. I don't understand half the interface requirements you've listed, so consider this an experimental answer that may not relate to your problem at all.
I suggest that you tell me what exactly is missing from my approach, and I can amend it. I'll omit templates for now, since they don't seem to be relevant to the problem.
So, without further ado, the simplest start uses a container of smart pointers:
#include <vector>
#include <memory>
struct Base
{
virtual void f();
};
typedef std::shared_ptr<Base> BasePtr;
typedef std::vector<BasePtr> BaseContainer;
struct DerivedA : Base
{
virtual void f();
// ...
};
// further derived classes
Usage:
int main()
{
BaseContainer v;
v.push_back(BasePtr(new DerivedB));
v.push_back(BasePtr(new DerivedC(true, 'a', Blue)));
BasePtr x(new DerivedA);
some_func(x);
x->foo()
v.push_back(x);
v.front()->foo();
}
If you happen to have some automatic object somewhere, you can insert a copy:
DerivedD d = get_some_d();
v.push_back(BasePtr(new DerivedD(d)));
To iterate:
for (BaseContainer::const_iterator it = v.begin(), end = v.end(); it != end; ++it)
{
(*it)->foo();
}
Update: If you want to initialize an object after construction, you can do something like this:
{
DerivedE * p = new DerivedE(x, y, z);
p->init(a, b, c);
v.push_back(BasePtr(p));
}
Or, if the init function is virtual, even simpler:
v.push_back(BasePtr(new DerivedE(x, y, z)));
v.back()->init(a, b, c);
2nd Update: Here's how a derived object might look like:
struct DerivedCar : Base
{
enum EType { None = 0, Porsche, Dodge, Toyota };
DerivedCar(EType t, bool a, unsigned int p)
: Base(), type(t), automatic_transmission(a), price(p)
{
std::cout << "Congratulations, you know own a " << names[type] << "!\n"; }
}
private:
EType type;
bool automatic_transmission;
unsigned int price;
static const std::unordered_map<EType, std::string> names; // fill it in elsewhere
};
Usage: Base * b = new DerivedCar(DerivedCar::Porsche, true, 2000);
3rd Update: This one is unconnected, just an illustration of how to use lookup tables in favour of switch statements. Suppose we have lots of similar functions (same signature) that we want to use based on some integer:
struct Foo
{
void do_a();
void do_b();
// ...
void do(int n)
{
switch (n) {
case 2: do_a(); break;
case 7: do_b(); break;
}
}
};
Instead of the switch, we can register all functions in a lookup table. Here I'm assuming C++11 support:
struct Foo
{
// ...
static const std::map<int, void(Foo::*)()> do_fns;
void do(int n)
{
auto it = do_fns.find(n);
if (it != do_fns.end()) { (this->**it)(); }
}
};
const std::map<nt, void(Foo::*)()> Foo::do_fns {
{ 3, &Foo::do_a },
{ 7, &Foo::do_b },
// ...
};
Basically, you turn static code into container data. That's always a Good Thing. This is now easily scalable; you just add new functions to the lookup map as they come along. No need to touch the actual do() code again!

Reference-counting instances of classes based on their types

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.