2016-03-25 6 views
1

Ich habe std::type_index verwendet, um eine std::unordered_map<std::type_index, MyProperty> in MyClass zu speichern. Jetzt möchte ich (mit boost :: serialization) MyClass serialisieren. Der Compiler sagt struct std::type_index has no member named serialize, die angibt, dass boost :: serialisierung std::type_index nicht unterstützt. Die Frage ist also, was in diesem Fall zu tun ist? Hat jemand eine serialize Funktion für std::type_index? Oder gibt es ein anderes Objekt, das für den Schlüssel für diese map verwendet werden kann, die ich brauche, die bereits serialisierbar ist, die die gleiche Art von Sache tun können. Wenn nämlich eine Funktion Vorlage tun I:Serialisierung `std :: type_index`

template <typename T> 
void MyClass::func(T) 
{ 
    myMap.find(std::type_index(typeid(T))); 
} 

Hier eine Demo des Mangels an Unterstützung ist:

#include <boost/archive/text_oarchive.hpp> 

#include <fstream> 
#include <typeindex> 

int main() 
{ 
    std::type_index myTypeIndex = typeid(double); 

    std::ofstream outputStream("test.txt"); 
    boost::archive::text_oarchive outputArchive(outputStream); 

    outputArchive << myTypeIndex; 
    outputStream.close(); 

    return 0; 
} 
+0

Gefahr. Minenfeld voraus. Sie möchten etwas indizieren, das Sie konstruieren können, und nicht etwas, das vom Compiler erstellt wird. Leider müssen Sie einen eigenen polymorphen, serialisierbaren Wrapper um Typid erstellen. –

+0

@RichardHodges Sie sagen mit 'std :: unordered_map ' im Allgemeinen ist eine schlechte Idee? Oder nur wenn es serialisiert werden muss? –

+0

Nein, type_index ist so konzipiert, dass Sie als Index verwendet werden können. Es ist einfach nicht kompatibel mit boost :: serialize, weil Sie die Konstruktion nicht kontrollieren. Sie müssen zumindest benutzerdefinierte Lade-/Speicherfunktionen dafür bereitstellen. –

Antwort

1

Schritt 1: Definieren Sie Ihre eigenen boost::serialization::load/save<> Überlastungen für std :: type_index

Schritt 2: bieten Sie eine Möglichkeit zum Zuordnen von Strings zu type_index und umgekehrt.

Schritt 3: Speichern Sie den type_index im Archiv in seinem Namen.

Sie müssen natürlich daran denken, den Namen jedes Typs zu registrieren, den Sie als Schlüssel in Ihrer Karte verwenden möchten. Im folgenden Beispiel würden Sie dies tun, indem Sie register_name("Foo", typeid(Foo)); usw. anrufen.

#include <iostream> 
#include <boost/archive/text_oarchive.hpp> 
#include <boost/serialization/split_free.hpp> 

#include <fstream> 
#include <sstream> 
#include <typeindex> 
#include <tuple> 
#include <vector> 
#include <string> 

struct nothing {}; 

using named_typeindex = std::tuple<std::string, std::type_index>; 
std::vector<named_typeindex> name_register = 
{ 
}; 

std::type_index type_for_name(const std::string& name) 
{ 
    auto i = std::find_if(std::begin(name_register), std::end(name_register), 
          [&name](const auto& entry) { return std::get<std::string>(entry) == name; }); 
    if (i == std::end(name_register)) 
     return typeid(nothing); 
    return std::get<std::type_index>(*i); 
} 

std::string const& name_for_type(std::type_index type) 
{ 
    auto i = std::find_if(std::begin(name_register), std::end(name_register), 
          [type](const auto& entry) { return std::get<std::type_index>(entry) == type; }); 

    using namespace std::string_literals; 
    if (i == std::end(name_register)) 
     throw std::logic_error("unregistered type "s + type.name()); 

    return std::get<std::string>(*i); 
} 

bool register_name(std::string name, std::type_index ti) 
{ 
    if (type_for_name(name) == typeid(nothing)) 
    { 
     name_register.push_back(std::make_tuple(std::move(name), ti)); 
     return true; 
    } 
    return false; 
} 

namespace boost { 
    namespace serialization { 

     template<class Archive> 
     void save(Archive & ar, const std::type_index & t, unsigned int version) 
     { 
      ar << name_for_type(t); 
     } 

     template<class Archive> 
     void load(Archive & ar, std::type_index & t, unsigned int version) 
     { 
      std::string s; 
      ar >> s; 
      t = type_for_name(s); 
     } 

    } // namespace serialization 
} // namespace boost 

BOOST_SERIALIZATION_SPLIT_FREE(std::type_index); 

int main() 
{ 
    std::type_index myTypeIndex = typeid(double); 

    std::ostringstream outputStream {}; 
    boost::archive::text_oarchive outputArchive(outputStream); 

    outputArchive << myTypeIndex; 

    std::cout << outputStream.str() << std::endl; 

    return 0; 
}