1

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:

http://coliru.stacked-crooked.com/a/d2a9b33dd9f15369

Community
  • 1
  • 1
tower120
  • 5,007
  • 6
  • 40
  • 88
  • *"Need this SET, because in C++11 auto can only be static const"* Not sure what you mean here. This sounds like class member declarations, but are there any class members here? – dyp May 18 '14 at 20:17
  • Seems like there could be a lifetime issue. Could you provide a short complete, compilable example? – dyp May 18 '14 at 20:19
  • "Need this SET, because in C++11 auto can only be static const" - Well, I want to change fields of plugins. If it will constexpr, I could not do that. I'll update question in a minute. – tower120 May 18 '14 at 20:25
  • `forward_as_tuple` is perfect forwarding not rvalue in its use of `&&`. As used above, it is equivalent to `tie`. If used with temporaries as above, UB results shortly. If used with `forward`, is pretty pointless. Only use `forward` and `forward_as_tuple` when forwarding, or if you understand their implementation. – Yakk - Adam Nevraumont May 19 '14 at 02:22
  • @Yakk I don't understand you. Why it is equivalent to tie? tie concatanate two tuples. What is "UB"? "forward_as_tuple is perfect forwarding not rvalue in its use of &&" - what do you mean? Well, we are forward our plugins to the final destination. Don't we? http://coliru.stacked-crooked.com/a/d2a9b33dd9f15369 – tower120 May 19 '14 at 09:21
  • 1
    `tie` makes a `tuple` of references, as does `forward_as_tuple`. They do different things with rvalue references. The `&&` in the `forward_as_tuple` is using the oerfect forwarding technique, it does not mean `='rvalue reference'. UB is undefined behaviour, and as your forward goes to an object whose lifetime exceeds the current line and who stores said references, you will be in trouble. – Yakk - Adam Nevraumont May 19 '14 at 13:09
  • @Yakk About 'UB' - objects are permanent look here http://coliru.stacked-crooked.com/a/d2a9b33dd9f15369 . " it does not mean `='rvalue reference'" - So you want to say that in my tuple, actually stored lvalue references (&) not rvalue(&&)? – tower120 May 19 '14 at 13:14
  • @Yakk - make an answer about tie and lvalue references it seems reasonable. And one more question - Can I think about 'rvalue references' as an references on TEMPORARY objects? – tower120 May 19 '14 at 13:17
  • No, I said if you used your syntax and passed it actual temporaries, your code would exhibit UB shortly. This is a sign that `forward_as_tuple` is a poor idea in your context: you are not forwarding (in the perfect forwarding sense), esp in the `decltype`. And no, this does not answer your question, it simply points out that you are using `forward_as_tuple` wrong, the question of 'tuple of references' or 'tuple of values' is orthogonal to this problem in your code. – Yakk - Adam Nevraumont May 19 '14 at 14:29

0 Answers0