I have some small "plugin system" (not sure this is right name). It allow you to store objects (plugins), and then call some methods from each of them. With this approach we have absolutely no overhead on iterating/object pass/callback call.
// Need this SET, because in C++11 auto can only be static const.
// And we may need to change them later.
#ifndef SET
#define SET(NAME, VALUE) decltype(VALUE) NAME = VALUE
#endif
Plugin1 plugin1(param1, param2);
Plugin2 plugin2(param1, param2);
Plugin3 plugin3(param1, param2);
SET(plugins, std::tie( // Pay attention here. We store &, not objects
plugin1,
plugin2,
plugin3
));
Then, when I need to call some function from each of plugins, or do something with each of then I iterate through plugins at compile time (I check this with generated asm code, it just call or even inline do_it
, without anything else) and call callback function (I not show iterate code here, it's trivial):
struct Call{
float k=0;
template<typename T, int Index> // lambda function not efficient than this. Tested -O2 clang, gcc 4.8
inline void do_it(T &&t){
std::cout << "value = " <<t << " ; " << "id = " << Index << std::endl;
}
};
And if I need to do something with specific plugin, I just directly use plugin1,plugin2, plugin3. No need to call std::get<>
. Plus IDE highlight available plugins when you type them.
Well, and the question is. Is it ok to store rvalue references on objects, or I have to store objects directly in my tuple? Like this:
SET(plugins, std::tuple(
Plugin1(param1, param2),
Plugin2(param1, param2),
Plugin3(param1, param2)
));
When I iterate, I pass plugin as usual reference:
struct Call{
float k=0;
template<typename T, int Index> // lambda function not efficient than this. Tested -O2 clang, gcc 4.8
inline void do_it(T &t){
std::cout << "value = " <<t << " ; " << "id = " << Index << std::endl;
}
};
With this approach we have additional move constructor calls for each element in tuple. Previous version is free.
I ask about this, because, previously I read about Data locality and now I worry about how data are placed in memory. Maybe I even not have to think this about...
UPDATE
1) Without "SET" we'll have something like this:
// in global scope
auto plugins = std::tie(
plugin1,
plugin2,
plugin3
);
And it's ok. Till it in global scope. But as only we want to put "plugins" as a class member, compiler will demand it as constexpr static, and it will become:
struct MyClass{
static const Plugin1 plugin1(param1, param2);
static const Plugin2 plugin2(param1, param2);
static const Plugin3 plugin3(param1, param2);
static const auto plugins = std::tie(
plugin1,
plugin2,
plugin3
);
};
Here Is it possible to have an "auto" member variable?
2) About life time... For the first case with &&. We hold objects separately, and our "plugins" hold only rvalue references to objects: