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.
Related
Suppose you're writing the base for multiple classes. When should you make the base class have all of the dependent operations be virtual and when should the class take a template argument which is a class with the traits necessary?
e.g.
class base
{
public:
virtual void do_run() = 0;
void general_do_run()
{
// general stuff
// then
do_run();
}
};
class child: public base
{
public:
void do_run() override {}
};
vs
template<class traits>
class base
{
public:
void general_do_run()
{
traits::do_run();
}
};
struct child_traits
{
void do_run() { }
};
class child: public base<child_traits>
{
};
I've noticed that the STL seldom uses virtuals (I assume because of the overhead).
In the virtual case I can write:
std::vector<std::unique_ptr<base>>
And I can use this to store multiple different derived classes.
In the template case there is no such straightforward way to store heterogeneous derived classes in a container and do anything useful with them. You'd have to use something like this:
std::vector<std::variant<child, child2, child3>>
Which is possible, but probably consumes more space, is less familiar to most C++ users, and is not at all flexible if someone else wants to add their own derived type without modifying the vector type.
Use virtual for runtime polymorphism. Use templates or other techniques for static (compile-time) polymorphism.
In addition to the answer from John:
Storing different types to a single vector and the potential higher memory consumption by using std::variant can be overcome by using a variant of pointer types like
std::vector< std::unique_ptr<A>, std::unique_ptr<B> >
I see a very big advantage on independent types and std::variant in the fact that we don't need a common base class. Even on heterogeneous classes we can store and do something with the elements. Even if they don't have any common base class or even they do not have a common interface at all!
struct A
{
void Do() { std::cout << "A::Do" << std::endl; }
};
struct B
{
void Do() { std::cout << "B::Do" << std::endl; }
void Foo() { std::cout << "B::Foo" << std::endl; }
};
struct C
{
void Foo() { std::cout << "C::Foo" << std::endl; }
};
int main()
{
using VAR_T = std::variant< std::unique_ptr<A>, std::unique_ptr<B> >;
std::vector<VAR_T> v;
v.emplace_back( std::make_unique<A>() );
v.emplace_back( std::make_unique<B>() );
for ( auto& el: v ) { std::visit( []( auto& el ){ el->Do(); }, el ); }
// You can combine also a vector to other unrelated types which is impossible
// in case of using virtual functions which needs a common base class.
using VAR2_T = std::variant< std::unique_ptr<B>, std::unique_ptr<C> >;
std::vector<VAR2_T> v2;
v2.emplace_back( std::make_unique<B>() );
v2.emplace_back( std::make_unique<C>() );
for ( auto& el: v2 ) { std::visit( []( auto& el ){ el->Foo(); }, el ); }
// and even if some class did not provide the functionality, we can deal with it:
// -> here we try to call Do which is only in type B!
for ( auto& el: v2 ) { std::visit(
[]( auto& el )
{
if constexpr ( requires { el->Do();} )
{
el->Do();
}
else
{
std::cout << "Element did not provide function!" << std::endl;
}
}
, el ); }
}
The argument that "feature xy is less familiar to most C++ users" is a common problem with all kind of domains. If you never had seen a hammer, it might be valid to use a stone to drive the nail. Best fit designs can only be done, if we know the toolset and how to use it. And education of teams is the best investment a tec company can do.
Back to the question what to prefer:
As always it depends on the algorithm you have to implement. If run time polymorphism is fine and fits, use it. If you can't, only as example cause of non common base class, you can drive with std::variant and std::visit.
And for all approaches CRTP comes into play to generate mixins in all its variants.
In programming in general, there is no general "x is always better as y" rule. Designs must fit! In maintainability, resource usage ( memory, time ) usability ...
I am trying to create a QList of a polymorphic type that still uses Qt's implicit sharing.
My specific use case is passing items held in a QList to QtConcurrent::mapped. The items all descend from a base class which defines a virtual function that QtConcurrent::mapped will call. The majority of the stored data will be child class specific. These items may be edited after the threading begins, leaving me with two main options, locks or copy the data. I do not want to stick locks in, because that would eliminate most of the purpose of using extra threads. Also making full copies of my data also seems quite undesirable. Instead I would like use Qt's implicit sharing to only make copies of the data items that I change, however I can't seem to make a QList of a polymorphic type that still uses implicit sharing.
QList by default uses implicit sharing, so at first glance it would seem that we are already done.
QList<Base> list;
Derived derived_obj;
list.append(derived_obj); // this fails
However appending a child class to a QList of the parent class will not work and the standard answer is to instead use a QList of QSharedPointers to the base class, which will accept appending a pointer to the child class.
QList<QSharedPointer<Base> > pointer_list;
QSharedPointer<Derived> derived_pointer;
pointer_list.append(derived_pointer); // this works but there is no copy-on-write
If I use a QList of QSharedPointers, it is the QSharedPointer that will be be copied rather than my polymorphic class, meaning that I have lost the copy-on-write functionality that I would like.
I have also looked at using a QList of QSharedDataPointers.
QList<QSharedDataPointer<Base> > data_pointer_list;
QSharedDataPointer<Derived> derived_data_pointer;
list.append(derived_data_pointer); // this fails
However like QList itself, QSharedDataPointers do not seem to accept polymorphic types.
This fails:
QList<QSharedDataPointer<Base>> list;
QSharedDataPointer<Derived> derived(new Derived);
list.append(derived);
Note An alternative approach to the below would be to merge the PolymorphicShared and PolymorphicSharedBase to add polymorphism support directly to QSharedDataPointer, without placing special requirements on the QSharedData-derived type (e.g. it wouldn't need to explicitly support clone). This requires a bit more work. The below is just one working approach.
QSharedDataPointer is indeed the answer you seek and can definitely hold polymorphic QSharedData. You need to separate the type into a hierarchy based on QSharedData, and another parallel hierarchy wrapping the QSharedDataPointer. The QSharedDataPointer is not usually meant to be used directly by the end user of a class. It's an implementation detail useful in implementing an implicitly shared class.
For efficiency's sake, a QSharedDataPointer is a small type that can be moved at the bit level. It's quite efficient when stored in containers of all sorts - especially in Qt containers that can utilize the type traits to be aware of this property. The size of a class using a QSharedDataPointer will usually double if we make it polymorphic itself, thus it helps not to do it. The pointed-to data type can be polymorphic, of course.
First, let's define a rather univeral base class PIMPL that you'll build the hierarchy on. The PIMPL class can be dumped into the debug stream, and cloned.
// https://github.com/KubaO/stackoverflown/tree/master/questions/implicit-list-44593216
#include <QtCore>
#include <type_traits>
class PolymorphicSharedData : public QSharedData {
public:
virtual PolymorphicSharedData * clone() const = 0;
virtual QDebug dump(QDebug) const = 0;
virtual ~PolymorphicSharedData() {}
};
The xxxData types are PIMPLs and are not meant for use by the end-user. The user is meant to use the xxx type itself. This shared type then wraps the polymorphic PIMPL and uses the QSharedDataPointer for storage of the PIMPL. It exposes the methods of the PIMPL.
The type itself is not polymorphic, to save on the size of the virtual table pointer. The as() function acts as dynamic_cast() would, by redirecting polymorphism to the PIMPL.
class PolymorphicShared {
protected:
QSharedDataPointer<PolymorphicSharedData> d_ptr;
PolymorphicShared(PolymorphicSharedData * d) : d_ptr(d) {}
public:
PolymorphicShared() = default;
PolymorphicShared(const PolymorphicShared & o) = default;
PolymorphicShared & operator=(const PolymorphicShared &) = default;
QDebug dump(QDebug dbg) const { return d_ptr->dump(dbg); }
template <class T> typename
std::enable_if<std::is_pointer<T>::value, typename
std::enable_if<!std::is_const<typename std::remove_pointer<T>::type>::value, T>::type>
::type as() {
if (dynamic_cast<typename std::remove_pointer<T>::type::PIMPL*>(d_ptr.data()))
return static_cast<T>(this);
return {};
}
template <class T> typename
std::enable_if<std::is_pointer<T>::value, typename
std::enable_if<std::is_const<typename std::remove_pointer<T>::type>::value, T>::type>
::type as() const {
if (dynamic_cast<const typename std::remove_pointer<T>::type::PIMPL*>(d_ptr.data()))
return static_cast<T>(this);
return {};
}
template <class T> typename
std::enable_if<std::is_reference<T>::value, typename
std::enable_if<!std::is_const<typename std::remove_reference<T>::type>::value, T>::type>
::type as() {
Q_UNUSED(dynamic_cast<typename std::remove_reference<T>::type::PIMPL&>(*d_ptr));
return static_cast<T>(*this);
}
template <class T> typename
std::enable_if<std::is_reference<T>::value, typename
std::enable_if<std::is_const<typename std::remove_reference<T>::type>::value, T>::type>
::type as() const {
Q_UNUSED(dynamic_cast<const typename std::remove_reference<T>::type::PIMPL&>(*d_ptr));
return static_cast<T>(*this);
}
int ref() const { return d_ptr ? d_ptr->ref.load() : 0; }
};
QDebug operator<<(QDebug dbg, const PolymorphicShared & val) {
return val.dump(dbg);
}
Q_DECLARE_TYPEINFO(PolymorphicShared, Q_MOVABLE_TYPE);
#define DECLARE_TYPEINFO(concreteType) Q_DECLARE_TYPEINFO(concreteType, Q_MOVABLE_TYPE)
template <> PolymorphicSharedData * QSharedDataPointer<PolymorphicSharedData>::clone() {
return d->clone();
}
A helper to makes it easy to use the abstract base class with derived data types. It casts the d-ptr to a proper derived PIMPL type, and forwards the constructor arguments to the PIMPL's constructor.
template <class Data, class Base = PolymorphicShared> class PolymorphicSharedBase : public Base {
friend class PolymorphicShared;
protected:
using PIMPL = typename std::enable_if<std::is_base_of<PolymorphicSharedData, Data>::value, Data>::type;
PIMPL * d() { return static_cast<PIMPL*>(&*this->d_ptr); }
const PIMPL * d() const { return static_cast<const PIMPL*>(&*this->d_ptr); }
PolymorphicSharedBase(PolymorphicSharedData * d) : Base(d) {}
template <typename T> static typename std::enable_if<std::is_constructible<T>::value, T*>::type
construct() { return new T(); }
template <typename T> static typename std::enable_if<!std::is_constructible<T>::value, T*>::type
construct() { return nullptr; }
public:
using Base::Base;
template<typename ...Args,
typename = typename std::enable_if<std::is_constructible<Data, Args...>::value>::type
> PolymorphicSharedBase(Args&&... args) :
Base(static_cast<PolymorphicSharedData*>(new Data(std::forward<Args>(args)...))) {}
PolymorphicSharedBase() : Base(construct<Data>()) {}
};
It's now a simple matter to have the parallel hierarchy of PIMPL types and their carriers. First, a basic abstract type in our hierarchy that adds two methods. Note how PolymorphicSharedBase adds the d() accessor of the correct type.
class MyAbstractTypeData : public PolymorphicSharedData {
public:
virtual void gurgle() = 0;
virtual int gargle() const = 0;
};
class MyAbstractType : public PolymorphicSharedBase<MyAbstractTypeData> {
public:
using PolymorphicSharedBase::PolymorphicSharedBase;
void gurgle() { d()->gurgle(); }
int gargle() const { return d()->gargle(); }
};
DECLARE_TYPEINFO(MyAbstractType);
Then, a concrete type that adds no new methods:
class FooTypeData : public MyAbstractTypeData {
protected:
int m_foo = 0;
public:
FooTypeData() = default;
FooTypeData(int data) : m_foo(data) {}
void gurgle() override { m_foo++; }
int gargle() const override { return m_foo; }
MyAbstractTypeData * clone() const override { return new FooTypeData(*this); }
QDebug dump(QDebug dbg) const override {
return dbg << "FooType-" << ref << ":" << m_foo;
}
};
using FooType = PolymorphicSharedBase<FooTypeData, MyAbstractType>;
DECLARE_TYPEINFO(FooType);
And another type that adds methods.
class BarTypeData : public FooTypeData {
protected:
int m_bar = 0;
public:
BarTypeData() = default;
BarTypeData(int data) : m_bar(data) {}
MyAbstractTypeData * clone() const override { return new BarTypeData(*this); }
QDebug dump(QDebug dbg) const override {
return dbg << "BarType-" << ref << ":" << m_foo << "," << m_bar;
}
virtual void murgle() { m_bar++; }
};
class BarType : public PolymorphicSharedBase<BarTypeData, FooType> {
public:
using PolymorphicSharedBase::PolymorphicSharedBase;
void murgle() { d()->murgle(); }
};
DECLARE_TYPEINFO(BarType);
We'll want to verify that the as() method throws as needed:
template <typename F> bool is_bad_cast(F && fun) {
try { fun(); } catch (std::bad_cast) { return true; }
return false;
}
The use of the implicitly shared types is no different than the use of Qt's own such types. We can also cast using as instead of dynamic_cast.
int main() {
Q_ASSERT(sizeof(FooType) == sizeof(void*));
MyAbstractType a;
Q_ASSERT(!a.as<FooType*>());
FooType foo;
Q_ASSERT(foo.as<FooType*>());
a = foo;
Q_ASSERT(a.ref() == 2);
Q_ASSERT(a.as<const FooType*>());
Q_ASSERT(a.ref() == 2);
Q_ASSERT(a.as<FooType*>());
Q_ASSERT(a.ref() == 1);
MyAbstractType a2(foo);
Q_ASSERT(a2.ref() == 2);
QList<MyAbstractType> list1{FooType(3), BarType(8)};
auto list2 = list1;
qDebug() << "After copy: " << list1 << list2;
list2.detach();
qDebug() << "After detach: " << list1 << list2;
list1[0].gurgle();
qDebug() << "After list1[0] mod: " << list1 << list2;
Q_ASSERT(list2[1].as<BarType*>());
list2[1].as<BarType&>().murgle();
qDebug() << "After list2[1] mod: " << list1 << list2;
Q_ASSERT(!list2[0].as<BarType*>());
Q_ASSERT(is_bad_cast([&]{ list2[0].as<BarType&>(); }));
auto const list3 = list1;
Q_ASSERT(!list3[0].as<const BarType*>());
Q_ASSERT(is_bad_cast([&]{ list3[0].as<const BarType&>(); }));
}
Output:
After copy: (FooType-1:3, BarType-1:0,8) (FooType-1:3, BarType-1:0,8)
After detach: (FooType-2:3, BarType-2:0,8) (FooType-2:3, BarType-2:0,8)
After list1[0] mod: (FooType-1:4, BarType-2:0,8) (FooType-1:3, BarType-2:0,8)
After list2[1] mod: (FooType-1:4, BarType-1:0,8) (FooType-1:3, BarType-1:0,9)
The list copy was shallow and the items themselves weren't copied: the reference counts are all 1. After the detach, all data items were copied but because they are implicitly shared, they only incremented their reference counts. Finally, after an item is was modified, it is automatically detached, and the reference counts drop back to 1.
I have a void pointer and I would like to get the content of what the pointer refers to.
void class :: method(void * pointer)
{
cout<<pointer; // The address which the pointer refers to.
cout<<?; //The content of where the pointer refers to.
}
The original type of pointer is unknown.
EDIT: The goal is to allow create a "generic method" which gets any type of argument, and do the same actions for each.
The limitation is that the method is virtual and therefore I cannot use template method.
You need to cast the void* back to its original type (ie. before it was cast to void*). Then you can dereference the pointer and use what it's pointing to.
Eg. :
void fun(void* ptr) {
int* iptr = (int*) ptr;
std::cout << *iptr;
}
int* iptr = new int(42);
fun(iptr);
One way to do this in a way that fits your specific use case, is to pass on the type information with the object using a generic type like boost::any :
#include <iostream>
#include <string>
#include <boost/any.hpp>
class Foo {
public :
virtual void fun(const boost::any& obj) {
if (typeid(int) == obj.type()) {
std::cout << boost::any_cast<int>(obj) << std::endl;
}
else if (typeid(std::string) == obj.type()) {
std::cout << boost::any_cast<std::string>(obj) << std::endl;
}
else {
std::cout << "unsupported type" << std::endl;
}
}
};
int main(void) {
Foo foo;
int i = 42;
std::string s = "str";
float f = 1.1f;
foo.fun(i);
foo.fun(s);
foo.fun(f);
return 0;
}
But that can get very verbose, depending on how many types you want to support.
This is impossible. The types in C++ are (mostly) a compile-time property. At runtime, types are unknown (they are erased).
However, RTTI exist, notably for instances of some class containing virtual methods.
There is no possible trick in general. You could redesign your program by having some kind of variant type, or by having a common root class from which all your objects inherit, etc etc, or by using union types (better have your own discriminated unions).
Put it another way: when the compiler see a void* pointer, it does not even know the size of the data pointed by that pointer.
Future C++ standards might propose some std::any container.
Maybe you could have something like a cheap discriminated union class like
class Int_or_String {
const bool isint;
union {
int n;
std::string s;
};
Int_or_String(const int i) : isint(true), n(i) {};
Int_or_String(const std::string &st): isint(false), s(st) {};
~Int_or_String() { if (isint) n=0; else
/*not sure*/ s.std::string::~std::string(); };
// much more is missing
};
I'm not even sure of the syntax to explicitly destroy a union member.
See e.g. this question on calling destructors explicitly
Perhaps the Qt object model might inspire you. Look also into its QVariant
The usual way is to define a root class in your program and adopt the convention that all your objects are inheriting this root class (or even that all your meaningful data are in objects derived from that root class). This requires a redesign of the whole thing.
So you would decide that your root class is e.g
class Root {
public:
virtual void out(std::ostream&s) =0;
virtual ~Root() =0;
/// other common methods
};
static inline std::ostream& operator << (std::ostream&o, const Root &r)
{ r.out(o); return o; }
class Integer : public Root {
const int num;
public:
Integer(int n) : Root(), num(n) {};
void out (std::ostream &o) { o << num ; };
/// etc...
}; // end class Num
class String : public Root {
const std::string str;
public:
String(const std::string& s) : Root(), str(s) {};
void out (std::ostream &o) { o << str ; };
/// etc...
}; // end class String
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.
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.