Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have a lot of subclasses of an abstract class Letter, like A, B, C, D, etc. Letter has an integer ID variable, and every subclass of Letter gets assigned a unique id.
I then have another class, call it Alphabet. Alphabet has an
list<shared_ptr<Letter>>
member. Here is the problem... I would like to elegantly add B's and C's or other subclasses of Letter to particular instances of Alphabets. I think the most convenient way to do this would be to use the integer id of subclass somehow. In other words, I want to be able to have something like Alphabet.addLetter(int id), so if I did alphabet1.add(14), it would somehow add a shared_ptr for class H to the list.
Is there an elegant way to do this, avoiding some huge if statement where that I need to constantly update every time I add or remove one of the B, C, D, E, etc. classes? I'm hoping there's some kind of template-solution, but I'm not very familiar with advanced c++ notions like factories and templates. The naive thing I wanted was some kind of vector/map that converted my ids into class names, so that I could do something like
list.push_back(shared_ptr<classVector(i)>(new classVector(i))
or something like that, though I have no idea if that's possible.
Thanks!
p.s. I just chose the Alphabet example because I didn't want to give unnecessary detail. Obviously I'm not trying to design alphabets in such a silly way, lol.
edit: I'm struggling to make this make sense. My goal is to be able to create new subclasses of Letter very quickly with minimal effort. I would like to avoid having to type out code that looks like...
list.push_back(shared_ptr<X>(...));
every time I make a new letter. Does this make sense at all?
This is pretty hard to follow, but I think what you want is something along the lines of the following:
// where make_unique<> is from C++14 in std:: or like:
template <typename T, typename ... TArgs>
std::unique_ptr<T> make_unique(TArgs &&... args) {
return std::unique_ptr<T>(new T(std::forward<TArgs>(args)...));
}
struct Letter {
virtual ~Letter() { }
virtual void foo() = 0;
};
template <unsigned int N> struct LetterCode; // Note: no default implementation!
struct Alphabet {
// Indexed access, if you'll have 1 of each type max:
std::vector<std::unique_ptr<Letter>> v;
// If you don't need parameters, as mentioned in comments below ...
template <unsigned int N>
void addLetterN() {
if (N > v.size() + 1) { v.resize(N + 1); }
v[N] = make_unique<LetterCode<N>::type>(); // see below ...
}
// If your coding is complete from 0...N, this does the whole shebang.
template <unsigned int N>
void addLettersN() {
addLetters<N - 1>();
addLetterN<N>();
}
template <>
addLettersN<0>() {
addLetterN<0>();
}
};
If you need numeric codes for something like deserialization and never need constructor arguments, you can use a type trait template like follows to statically 'register' the types:
struct B : Letter {
B(int n, bool b, char const *name);
void foo() override;
};
template <> struct LetterCode<2> { using type = B; };
struct C : Letter {
C(double d);
void foo() override;
};
template <> struct LetterCode<3> { using type = C; };
void bar() {
Alphabet a;
a.addLetterN<2>();
a.addLetterN<3>();
// --OR--
a.addLettersN<3>(); // will do 0...3 in one fell swoop.
for (auto &i : a.v) {
if (!i) { continue; } // v is sparse, unlike l
i->foo();
}
If you need generalized constructor argument passing, you can use perfect forwarding, which is designed for cases like this and obviates the need for enum IDs, etc., from older styles of factories:
struct Alphabet {
std::list<std::unique_ptr<Letter>> l;
// variadic factory that chucks new (shared_ptr) objects in the list.
template <typename T, typename ... TArgs>
void addLetter(TArgs && ... args) {
l.push_back(make_unique<T>(std::forward<TArgs>(args)...));
}
};
void baz() {
Alphabet a;
a.addLetter<B>(1, false, "pony");
a.addLetter<C>(2.718281828);
for (auto &i : a.l) {
i->foo(); // can call virtual funcs here all you want ...
}
}
This is relatively easy if I understood you correctly, using what's called a factory-pattern.
If you can list all of the derived types:
Letter header:
struct Letter {
enum LetterEnum {LetterA, LetterB, LetterC, LetterCount};
virtual ~Letter() {} //base types should always have virtual destructor
virtual void foo() = 0;
static std::unique_ptr<Letter> construct(LetterEnum c);
};
Implementation headers:
struct A : Letter {
void foo() override;
};
struct B : Letter {
void foo() override;
};
struct C : Letter {
void foo() override;
};
Letter body:
std::unique_ptr<Letter> Letter::construct(Letter::LetterEnum c)
{
switch(c) {
case Letter::LetterA : return make_unique<A>();
case Letter::LetterB : return make_unique<B>();
case Letter::LetterC : return make_unique<C>();
default: throw ...;
}
}
Usage:
int main() {
char c;
std::cin >> c;
//get a letter of the derived type associated with the letter entered
std::unique_ptr<Letter> ptr = Letter::construct(c);
}
If you can't list all of the derived types:
Allow the derived types to register themselves with the Letter class, and then Letter can use that to create each of the derived types. This way, adding and deleting the derived types involves no changes to any other files. Easy!
struct Letter {
virtual ~Letter() {} //destructor is always virtual when inheretence is involved
....
//this is a "shared" function in the Letter class itself
//it takes a letter, and returns a dynamically allocated instance
//of the derived type corresponding with that letter
static std::unique_ptr<Letter> construct(char c);
//this typedef represents the actual function that returns
//each dynamically allocated derived type
typedef std::function<std::unique_ptr<Letter>()> letter_ctor;
//this is a "shared" function in the Letter class itself
//it takes a letter, and a function that creates derived types,
//and saves them inside the container ctors
static bool register(char c, letter_ctor func);
private:
//this is a "shared" member in the Letter class.
//There is only one shared by all of the Letters. Like a global.
//When you give it a letter, it gives you a function.
//and is VERY fast for large numbers of entries
static std::unordered_set<char,letter_ctor> ctors;
};
and in your implementation file:
//here's the function that derived types register themselves with
//pretty straightforward, just inserts the pair into the unordered_map
bool Letter::register(char c, Letter::letter_ctor func)
{return Letter::ctors.insert(std::make_pair(c,std::move(func))).second;}
//and here's the function that creates the derived types
//it checks if the letter is in the unordered_map
//if the letter isn't there, it throws an exception
//otherwise, it calls the function associated with that letter
//which creates the derived type on the heap, and returns a pointer to it
std::unique_ptr<Letter> Letter::construct(char c)
{
auto it = Letter::ctors.find(c);
if (it == Letter::ctors.end())
throw ...;
return it->second(); //construct that letter
}
and then your derived types do this:
//you know this part
struct LetterA : public Letter
{
....
};
//derived types have to register themselves:
//this is a global, so when the program loads, it automatically calls this
//even before main runs*
//it registers the letter 'A' and a function that creates a LetterA class on the heap
static bool registerA = Letter::register('A', [](){return make_unique<LetterA>();});
and then you can easily create arbirary derived types!
int main() {
char c;
std::cin >> c;
//get a letter of the derived type associated with the letter entered
std::unique_ptr<Letter> ptr = Letter::construct(c);
}
*It doesn't always get called before main. If you have problems, put an bool init_A(); in the A header, and bool init_A(){return true;} in the A implementation file, and in your main file have static bool AInit=init_A(); which should force it. This is almost never needed in practice though.
As a side note, these depend on having a make_unique, which should have been in C++11, but was left out due to oversight. It will be in C++14. In the meantime, use this:
template<class T, class...Us>
std::unique_ptr<T> make_unique(Us&&...us)
{return std::unique_ptr<T>(new T(std::forward<Us>(us)...));}
My understanding is that you want to create a instance of one of the classes, dependend on an id which relates to the class from which an instance should be created.
If so, please have a look for factory pattern. There are a lot of factory implementations, also based on template recursive expansion of a typelist.
Pseudo Code:
Factory<A,B,C,D> fac; // the list must be changed, if some more classes comes and goes
id_type id;
list<base> l;
l.push_back=fac.Create(id);
It is also quite simple to implement such a class yourself.
The goal is simple: create the function factories that returns an array of Alphabet makers.
The index of the letter and the index into the array will be the same.
Ideally, we want to auto-generate said index without having to manually set it.
#include <memory>
#include <vector>
#include <iostream>
template<class T>using Type=T;
template<class...Ts>struct types:std::integral_constant<unsigned,sizeof...(Ts)>
{typedef types type;};
template<class T,class types>struct index_of;
template<class T,class T0, class...Ts>struct index_of<T,types<T0,Ts...>>:
std::integral_constant<unsigned,index_of<T,types<Ts...>>::value+1>
{};
template<class T,class...Ts>struct index_of<T,types<T,Ts...>>:
std::integral_constant<unsigned,0>
{};
template<unsigned,class types>struct type_at;
template<unsigned N, class T,class...Ts>struct type_at<N,types<T,Ts...>>:
type_at<N-1,types<Ts...>> {};
template<class T,class...Ts>struct type_at<0,types<T,Ts...>>{
typedef T type;
};
template<unsigned N,class types>
using type_at_t=typename type_at<N,types>::type;
template<template<class>class Target,unsigned N,class types>
struct nth_apply;
template<template<class>class Target,unsigned N,class...Ts>
struct nth_apply<Target,N,types<Ts...>>{
typedef Target<type_at_t<N,types<Ts...>>> type;
};
template<template<class>class Target,unsigned N,class types>
using nth_apply_t=typename nth_apply<Target,N,types>::type;
This is the type that produces the function pointers for us:
template<class T>struct shared_maker{
template<class...Args>
std::shared_ptr<T> operator()(Args&&...args)const{
return std::make_shared<T>(std::forward<Args>(args)...);
}
template<class R, class... Args>
operator Type<R(Args...)>*() const{
return [](Args... args)->R{
return shared_maker{}(std::forward<Args>(args)...);
};
}
};
Here is what we do for the actual letter types. We forward declare them:
struct A; struct B; // etc
Stick them into a list of types:
typedef types<A,B> Alphabet_Types;
Now, our simple test Alphabet type:
struct Alphabet {
virtual unsigned get_index() const = 0;
};
And a CRTP helper that gets the index of the letter from its offset into the list of types! The virtual get_indexes is just for debugging:
template<class D>
struct Letter:Alphabet{
static const unsigned index = index_of<D, Alphabet_Types>::value;
virtual unsigned get_index() const override { return index; }
};
Now the signature of our array-producer:
typedef std::shared_ptr<Alphabet> spAlphabet;
std::array<spAlphabet(*)(), Alphabet_Types::value> factories();
Here is how we define our (toy) letter classes:
struct A:Letter<A>{};
struct B:Letter<B>{};
ie, use Letter<> as a CRTP base instead of Alphabet.
The only thing left is to write the function factories.
Index boilerplate. C++1y has a replacement:
template<unsigned...>struct indexes{typedef indexes type;};
template<unsigned Max, unsigned... Is> struct make_indexes:make_indexes<Max-1,Max-1,Is...>{};
template<unsigned...Is>struct make_indexes<0,Is...>:indexes<Is...>{};
The actual implementation via a helper function. We get a pack of indexes and expand it, building our std::array of function pointers from our shared_maker above instantiated with an indexed type from the Alphabet_Types we wrote above:
template<unsigned...Is>
std::array<spAlphabet(*)(), Alphabet_Types::value> factories(indexes<Is...>){
return {nth_apply_t<shared_maker,Is,Alphabet_Types>{}...};
}
The actual factories function just forwards to the above helper:
std::array<spAlphabet(*)(), Alphabet_Types::value> factories(){
return factories(make_indexes<Alphabet_Types::value>{});
}
And some trivial test code:
int main() {
std::vector<spAlphabet> vec;
auto builders = factories();
for (int i = 0; i < 2; ++i) {
vec.push_back(builders[i]());
}
for( auto&& ptr:vec ) {
std::cout << ptr->get_index() << "\n";
}
}
Related
I recently found out that the .* operator (and the closely related ->* operator) exists in C++. (See this question.)
Seems neat at first, but why would I ever need such a thing? The two answers in the linked question provided contrived examples which would benefit from a direct function call.
Where a direct function call is inconvenient, a function object could be used instead, like the lambda functions that may be used in std::sort. This removes a level of indirection and hence would be more performant than using .*.
The linked question also mentioned a simplified version of this example:
struct A {
int a;
int b;
};
void set_member(A& obj, int A::* ptr, int val){
obj.*ptr = val;
}
int main()
{
A obj;
set_member(obj, &A::b, 5);
set_member(obj, &A::a, 7);
// Both members of obj are now assigned
}
But it's pretty trivial (perhaps even better practice because it's cleaner and isn't unnecessarily constrained to members of A) to do this instead:
struct A {
int a;
int b;
};
void set_me(int& out, int val){
out = val;
}
int main()
{
A obj;
set_me(obj.b, 5);
set_me(obj.a, 7);
// Both members of obj are now assigned
}
In conclusion, a pointer-to-member-function might be replaced by a function object, and a pointer-to-member-variable might be replaced by a direct reference of said variable or a function object. Doing so might also increase the efficiency of the code due to one less indirection.
This question only provides examples where my conclusion stands, so it does not answer my question.
Apart from interfacing legacy code which uses .* (in which there would be no choice at all), when, really, would I want to use .*?
Your example is too trivial to be illustrative. Consider a bit more complicated one
struct A {
int a;
int b;
};
void set_n_members(A objs[], unsigned n, int A::* ptr, int val)
{
for (unsigned i = 0; i < n; ++i)
objs[i].*ptr = val;
}
int main()
{
A objs[100];
set_n_members(objs, 100, &A::b, 5);
set_n_members(objs, 100, &A::a, 7);
}
How would you rewrite this without int A::* ptr and without inducing code bloat?
You could create collections of pointers to members and iterate over them. E.g.:
struct UserStrings
{
std::string first_name;
std::string surname;
std::string preferred_name;
std::string address;
};
...
std::array<std::string UserStrings::*, 4> str_cols = { &UserStrings::first_name, &UserStrings::surname, &UserStrings::preferred_name, &UserStrings::address };
std::vector<UserStrings> users = GetUserStrings();
for (auto& user : users)
{
for (auto& column : str_cols)
{
SanitizeForSQLQuery(user.*column);
}
}
It is used to implement std::mem_fn, which is used to implement std::function.
The following code shows how the ->* operator works in a naive Function class implemention.
Similarly, you can implement a member invoker class using the .* operator and a class reference.
#include <iostream>
class A
{
public:
void greet()
{
std::cout << "Hello world"<<std::endl;
}
};
template<typename R, typename ...TArgs>
class Invoker
{
public:
virtual R apply(TArgs&& ...args) = 0;
};
template<typename C, typename R, typename ...TArgs>
class MemberInvoker :public Invoker<R, TArgs...>
{
protected:
C* sender;
R(C::*function)(TArgs ...args);
public:
MemberInvoker(C* _sender, R(C::*_function)(TArgs ...args))
:sender(_sender)
, function(_function)
{
}
virtual R apply(TArgs&& ...args) override
{
return (sender->*function)(std::forward<TArgs>(args)...);
}
};
template<typename T>
class Func
{
};
template<typename R, typename ...TArgs>
class Func<R(TArgs...)>
{
public:
Invoker<R,TArgs...>* invoker=nullptr;
template<typename C>
Func(C* sender, R(C::*function)(TArgs...))
{
invoker =new MemberInvoker<C, R, TArgs...>(sender, function);
}
R operator()(TArgs&& ...args)
{
return invoker->apply(std::forward<TArgs>(args)...);
}
~Func()
{
if (invoker)
{
delete invoker;
invoker = nullptr;
}
}
};
int main()
{
A a;
Func<void()> greetFunc(&a, &A::greet);
greetFunc();
system("PAUSE");
}
Let's say you wanted to write a LINQ style library for C++ that could be used something like this:
struct Person
{
std::string first_name;
std::string last_name;
std::string occupation;
int age;
int children;
};
std::vector<Person> people = loadPeople();
std::vector<std::string> result = from(people)
.where(&Person::last_name == "Smith")
.where(&Person::age > 30)
.select("%s %s",&Person::first_name,&Person::last_name);
for(std::string person : result) { ... };
Under the covers, the where function accepts an expression tree containing a pointer to member (among other stuff) and is applied to each vector item looking for one that matches. The select statement accepts a format string and some pointer to members and does an sprintf style formatting of whichever vector items get through the where statements.
I have written something like this, and there are several others out there that do it slightly differently (Is there a LINQ library for C++?). Pointer-to-member allows the library user to specify whichever members of their struct that they want and the library doesn't need to know anything about what they might do.
Currently, I have an interface and several concrete implementation class, and I got string type user input.
I want to new corresponding class according to user input. What is the best practice to do these stuff?
It seems that the "factory patten" can be used for this. Now, I use an enum, an unordered_function and a specific function to handle it, the code is like below:
class IStrategy{};
class A : public IStrategy{};
class B : public IStrategy{};
class C : public IStrategy{};
class D : public IStrategy{};
enum StrategyEnum
{
A = 0,
B,
C,
D,
};
const std::unordered_map<std::string, StrategyEnum> ms_lut{
{"A", A},
{"B", B},
{"C", C},
{"D", D}};
Strategy* get_strategy(StrategyEnum s)
{
Strategy* s;
switch(s)
{
case A:
s = new A;
break;
case B:
s = new B;
break;
case C:
s = new C;
break;
case D:
s = new C;
break;
default:
cerr << "Unsupported strategy!" << endl;
}
return s;
}
What's more, in my current situation, all derived class have the same constructor parameter, what if different class has different constructor parameter?
It's not clear how the enum is helping you here:
It seems like duplication, as it's basically doing a translation that the factory could (so you have one translation of user input to enum, and one translation of enum to class)
It constricts you to use use only things that can be enumerated (e.g., you can't pass now to the ctor "everything except the last 3 digits from the user input", because that's not something that's enumerable).
Instead, how about making the factory depend on the user input? You could do very versatile stuff:
Strategy* get_strategy(const string &s)
{
// If the input is "foo", return A{}
if(s == "foo")
return new A{};
// If the input starts with "bar", return B{s}
if(s.substr(0, 3) == "bar")
return new B{s}
// etc.
How far do you want to go?
We could create a compile-time mapping from strategies, a magic switch that maps run time to compile time values, a layered input processing system that intelligently picks between various meta-factories, etc.
Me? If your enum and your strategies are tightly coupled, make it tighter:
class IStrategy{};
enum class StrategyEnum {
A = 0,
B,
C,
D,
Strategy_Count, // must be LAST in enum
};
template<StrategyEnum> class Strategy;
template<> class Strategy<A>: public IStrategy {};
template<> class Strategy<B>: public IStrategy {};
template<> class Strategy<C>: public IStrategy {};
template<> class Strategy<D>: public IStrategy {};
Then if you have a magic switch hanging around, get_strategy can be auto-written for you.
IStrategy* pStrat = magic_switch( eStrat, [&](auto strat)->IStrategy* {
constexpr StrategyEnum e = static_cast<StrategyEnum>(static_cast<std::size_t>(strat));
return new Strategy<e>{};
});
which has less code duplication than the switch/case you wrote, especially if the number of types starts to get bigger. But the boilerplate of magic_switch is large and complex and tricky.
Now, if your strategies need different data, you need a way to provide it to them. The easiest way would be to produce a data-source structure of some kind from which each can get the data they need.
Then either they have a constructor that takes a data source, or you write a function that takes the data-source, gets the data it needs, then constructs the object.
However, the #1 rule is "you probably won't need it". Figure out what you need. Hide the details. Implement and ship. All of the above is serious over-engineering.
Here is a magic switch:
template<std::size_t count>
struct magic_switch_t {
private:
template<std::size_t I>
using Index = std::integral_constant<std::size_t, I>;
template<class F>
using R=std::result_of_t<F&(Index<0>)>;
template<class F, std::size_t...Is>
R<F> invoke( std::index_sequence<Is...>, std::size_t i, F&& f ) const {
using pf = R<F>(*)(F&);
pf table[] = {
+[](F& f)->R<F>{ return std::forward<F>(f)(Index<Is>{}); }...
};
return table[i](f);
};
public:
template<class F>
R<F> operator()( std::size_t i, F&& f) const {
return invoke( std::make_index_sequence<count>{}, i, std::forward<F>(f) );
}
};
which takes a count and an index and a lambda, then invokes the lambda with the compile-time value of the index (assuming it is less than count) and returns the result.
Using this you can convert the run-time value of what enum the user picked, to a compile-time known enum value. Then you can map that compile-time known enum value to the proper constructor code.
In effect, this lets you synthesize the get_strategy boilerplate.
It is overengineering, but an option.
Note that some otherwise fine C++ compilers fail on the above legal code. On them, you need to write the lambda used in invoke manually as a non-anonymous type. A bit of extra boilerplate, but nothing tricky.
What I am needing can be done by storing this pointer of enclosing class into nested class for example this way:
class CEnclosing {
public:
class CNested : public CSomeGeneric {
public:
CNested(CEnclosing* e) : m_e(e) {}
virtual void operator=(int i) { m_e->SomeMethod(i); }
CEnclosing* m_e;
};
CNested nested;
CEnclosing() : nested(this) {}
virtual void SomeMethod(int i);
};
int main()
{
CEnclosing e;
e.nested = 123;
return 0;
}
This works well, but requires sizeof(void*) bytes of memory more for each nested member class. Exist effective and portable way to do this without need to store pointer to instance of CEnclosing in m_e?
As stated previously, C++ does not provide any way to do this. A nested class has no special way to find its enclosing class. The solution you already have is the recommended way.
If you have an advanced scenario, and if you are prepared to maintain non-portable code, and if the cost of storing an additional pointer is important enough to use a risky solution, then there is a way based on the C++ object model. With a number of provisos I won't go into, you can rely on the enclosing and nested classes being laid out in memory in a predictable order, and there being a fixed offset between the start of the enclosing and nested classes.
The code is something like:
CEnclosing e;
int offset = (char*)&e.nested - (char*)&e;
//... inside nested class
CEnclosing* pencl = (CEnclosing*)((char*)this - offset);
OTOH it's equally possible that the offsetof macro may just do it for you, but I haven't tried it.
If you really want to do this, read about trivially copyable and standard layout in the standard.
I believe the following could be portable; though it is not fool-proof. Specifically, it will not work across virtual inheritance.
Also, I would like to point that it is not safe, in that it will happily compile even if the member you pass does not correspond to the one you compute the offset with:
#include <iostream>
template <typename C, typename T>
std::ptrdiff_t offsetof_impl(T C::* ptr) {
C c; // only works for default constructible classes
T* t = &(c.*ptr);
return reinterpret_cast<char*>(&c) - reinterpret_cast<char*>(t);
}
template <typename C, typename T, T C::* Ptr>
std::ptrdiff_t offsetof() {
static std::ptrdiff_t const Offset = offsetof_impl(Ptr);
return Offset;
}
template <typename C, typename T, T C::* Ptr>
C& get_enclosing(T& t) {
return *reinterpret_cast<C*>(reinterpret_cast<char*>(&t)
+ offsetof<C, T, Ptr>());
}
// Demo
struct E { int i; int j; };
int main() {
E e = { 3, 4 };
//
// BEWARE: get_enclosing<E, int, &E::j>(e.i); compiles ERRONEOUSLY too.
// ^ != ^
//
E& ref = get_enclosing<E, int, &E::j>(e.j);
std::cout << (void const*)&e << " " << (void const*)&ref << "\n";
return 0;
}
Still, it does run on this simplistic example, which allowed me to find 2 bugs in my initial implementation (already). Handle with caution.
The clear and simple answer to your question is no, C++11 doesn't have any special feature to handle your scenario. But there is a trick in C++ to allow you to do this:
If CEnclosing didn't have a virtual function, a pointer to nested would have the same value as a pointer to the containing instance. That is:
(void*)&e == (void*)&e.nested
This is because the variable nested is the first in the class CEnclosing.
However, since you have a virtual function in CEnclosing class, then all you need to do is subtract the vtable size from &e.nested and you should have a pointer to e. Don't forget to cast correctly, though!
EDIT: As Stephane Rolland said, this is a dangerous solution and, honestly, I wouldn't use it, but this is the only way (or trick) I could think of to access the enclosing class from a nested class. Personally, I would probably try to redesign the relation between these two classes if I really want to optimise memory usage up to the level you mentioned.
How about using multiple inheritance like this:
class CNested {
public:
virtual void operator=(int i) { SomeMethod(i); }
virtual void SomeMethod(int i) = 0;
};
class CEnclosing: public CSomeGeneric, public CNested {
int nEncMember;
public:
CNested& nested;
CEnclosing() : nested(*this), nEncMember(456) {}
virtual void SomeMethod(int i) { std:cout << i + nEncMember; }
};
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);
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.