Search code examples
c++templatesdata-distribution-serviceopensplice

Creating containers for OpenSplice templates?


I'm trying to build a C++ program in OpenSplice that allows a user to specify the types that should be loaded in. This is complicated slightly by the C++ files generated through the use of OpenSplice's IDL pre-processor (IDLPP) not sharing a common interface or base class- instead opting to generate all/most of the code (I assume to cut down on unnecessary dependencies).

The solution I've created to this problem is to first generate a header file with a python script, that can then be called by the main program. This would allow all of the include statements to be generated, and the types created by IDLPP to be added as defines. The issue with this is then referencing those defines later on. I'd like to solve this by storing the defined objects in a container and then simply referencing them by number.

The problem here is that, as they don't share a common base class, C++ doesn't provide an easy way to store them in the same container. For reference, OpenSplice objects are generally created like so (semi-analogously to tuples, or vectors, in the STL):

dds::topic::Topic<moduleName::classType> variableName(params);

I'd like to store these different object types in a single container. Repetitive and 'ugly' code isn't much of an issue here, as I'm generating these files anyway. This is my current attempted implementation:

#include <tuple>

template<class T, class U>
class TopicHolder{
public:
    std::tuple<dds::topic::Topic<T>, dds::topic::Topic<U>> tuple_;

    //empty constructor (error: no matching function for call to 'std::tuple<dds::topic::Topic<chat::NameServiceType, dds::topic::detail::Topic>,
    //  dds::topic::Topic<chat::ChatMessageType, dds::topic::detail::Topic>>::tuple()')
    TopicHolder(){}

    //or leave out the default constructor altogether (error: use of deleted function + note: implicity deleted because the default definition would be ill formed)
    //also previous error   

    //put the template in the constructor? (see main below for issues)
    TopicHolder(T, U){
        dds::domain::DomainParticipant dp(0);
        dds::topic::Topic<T> top1(dp, "top1");
        dds::topic::Topic<U> top2(dp, "top2");
        tuple_ = std::make_tuple(top1, top2);
    }

    void storeTopics(std::tuple<dds::topic::Topic<T>, dds::topic::Topic<U>> topics){
        tuple_ = topics;
    }
};

int main(){
    //call templated constructor?
    TopicHolder<chat::NameServiceType, chat::ChatMessageType> topicHolder();
    //all good, now try to pull tuple out...
    auto outTopic = std::get<0>(topicHolder.tuple_);
    //error: request for member 'tuple_' in 'topicHolder', which is of non-class type 'TopicHolder<chat::NameServiceType, chat::ChatMessageType>()'
    //leave out brackets in TopicHolder constructor: error: no matching function for call to 'TopicHolder<chat::NameServiceType, chat::ChatMessageType>::Topic()'

    return 0
}

As you can see from the comments, this creates a variety of different errors depending on the parts I've tried to modify. It seems that the closest approach is one using the TopicHolder(T, U) constructor, but this fails when I try to actually read the tuple


Solution

  • You have vexing parse issue with

    // Function declaration
    TopicHolder<chat::NameServiceType, chat::ChatMessageType> topicHolder();
    

    Either use TopicHolder<chat::NameServiceType, chat::ChatMessageType> topicHolder; or TopicHolder<chat::NameServiceType, chat::ChatMessageType> topicHolder{};

    Then, you member seems not default construtible, so you have to use initializer list (which is good anyway).

    You might so do:

    template<class T, class U>
    class TopicHolder{
    public:
        dds::domain::DomainParticipant dp_{0};
        std::tuple<dds::topic::Topic<T>, dds::topic::Topic<U>> tuple_;
    
        TopicHolder() : tuple_{dds::topic::Topic<T>(dp, "top1"), dds::topic::Topic<U>(dp, "top2")} {
        }
    
        void storeTopics(std::tuple<dds::topic::Topic<T>, dds::topic::Topic<U>> topics){
            tuple_ = topics;
        }
    };
    
    int main(){
        TopicHolder<chat::NameServiceType, chat::ChatMessageType> topicHolder;
    
        auto& outTopic = std::get<0>(topicHolder.tuple_);
        // ...
    }