SFINAE ошибка сериализации общего указателя - PullRequest
0 голосов
/ 03 июня 2019

Я пытаюсь специализировать шаблон сериализации boost для общего указателя на объекты с определенным базовым классом, используя boost 1.58, gcc 5.4 в режиме c ++ 14. Я считаю, что у меня есть правильная настройка SFINAE, чтобы специализировать функцию, но компилятор не выберет функцию, как я ожидаю.

#include <memory>
#include <fstream>
#include <boost/archive/binary_oarchive.hpp>

class Artifact {
public:
  Artifact() {}
  virtual ~Artifact() {} // make polymorphic
};

class TestArtifact: public Artifact {
public:
  TestArtifact() : Artifact() {}
};


namespace boost {
namespace serialization {
template <class Archive, class T>
void serialize(Archive &ar,
               std::shared_ptr<typename std::enable_if<std::is_base_of<Artifact,T>::value,T>::type>& artifact,
               //std::shared_ptr<T>& artifact,
               unsigned int version) {
  // save common Artifact structure on save ...

  // Use factory to create specific Artifact (like TestArtifact) shared pointer
  // from common Artifact info on load
}

}
}

int main(int argc, char** argv) {
  auto t = std::make_shared<TestArtifact>();

  std::cout << typeid(std::shared_ptr<TestArtifact>).name() << std::endl;
  std::cout << typeid(std::shared_ptr<typename std::enable_if<std::is_base_of<Artifact,TestArtifact>::value,TestArtifact>::type>).name() << std::endl;

  std::ofstream ofs(argv[1]);
  boost::archive::binary_oarchive ar(ofs);
  ar << t;
}

Когда я собираю этот код (с g ++ -std = c ++ 14 -o test_template test_template.cpp -lboost_system -lboost_serialization), я получаю следующую ошибку (после обычного почти бесконечного списка «требуемых из»),

/usr/include/boost/serialization/access.hpp:118:9: error: ‘class std::shared_ptr<TestArtifact>’ has no member named ‘serialize’
         t.serialize(ar, file_version);

Это говорит о том, что я не правильно настраиваю SFINAE. Когда я переставляю закомментированную строку, чтобы специализироваться на std::shared_ptr<T>, код собирается и запускается, как и ожидалось, но я не хочу топать стандартную специализацию сериализации стандартного общего указателя boost. Когда я работаю с чрезмерно общей специализацией и печатаю идентификатор типа std::shared_ptr<TestArtifact> и вывод класса SFINAE, они совпадают (с этим компилятором я получаю вывод St10shared_ptrI12TestArtifactE для обоих), поэтому я не понимаю, почему моя функция сериализации SFINAE не распознается.

1 Ответ

2 голосов
/ 03 июня 2019

Проблема в том, что T не может быть выведено здесь.

Вместо ввода std::enable_if в параметре функции, поместите его в отдельный параметр шаблона.

template <class Archive, class T, typename std::enable_if<std::is_base_of<Artifact,T>::value>::type* = nullptr>
void serialize(Archive &ar, std::shared_ptr<T>& artifact, unsigned int version) { ... }
...