c++c++17stdany

Transfer data from library to upper level and then back without naming it inbetween


I need to get some complex data from a library then use this data at the upper level. The data consists of 2 parts: while evaluating the data A, i get some additional data B, and the data B should be returned back in the library "as is" in order to not reevaluate it again.

So to simplify this: i get data A and data B from the library, transfer both to the upper level, use A, but then i should transfer data B back to the library.

The problem is (apart from this weird architecture) i don't want my upper level to know anything about data B, so what mechanism should i use to avoid defining library-specific data types in the upper level code? Data should be passed as a pointer.

Im thinking about void*, but C++17 allows to use std::any which i dont understand quite enough. Can i use std::unique_ptr<std::any>? Or is it just std::any instead?

Should it be like that?

std::any GetDataAandB() 
{
    std::unique_ptr ret = std::make_unique<LibraryType>(1, "");
    return std::make_any<std::unique_ptr<LibraryType>>( ret);
}

Solution

  • How about

    using LibraryData = std::pair<A, std::any>;
    
    // Get aata of type A and B, store B in std::any -> hiding it's type
    // and return both values, but with B's type hidden
    LibraryData GetDataAandB()
    {
       A someValue;
       B someValueB_HiddenType;
       return LibraryData(A, std::any(B));
    }
    
    
    // Work with the first part of the Data
    void ConsumeData(const LibraryData &data)
    {
       // return the data to the library
       callLibrary(data);
    
     
       // or do something with the individual part A
       const A& dataOfTypeA = data.first;
       dataOfTypeA.SomeMethod();
    
       // Cannot really do anything with 'B', since its type is hidden
       const std::any& dataOfUnknownType = data.second;
    
       // create a new LibraryData object
       LibraryData newData(dataOfTypeA, dataOfUnknownType);
    
       callLibrary(newData);
    
    
       // Or, in case we can "guess" the type:
       try {
          B shouldBeB=std::any_cast<B>(data.second);
          // do something with B
       }
       catch (std::exception &e) {
          // Nope, it's not of type B.
          // std::any_cast will throw a bad_any_cast exception
       }
    }
    

    std::any takes care of any pointers required, so you don't have to add a unique_ptr