Нетипичный параметр шаблона и std :: enable_if_t - PullRequest
0 голосов
/ 08 февраля 2019

Я пытаюсь сделать некоторые постоянные вещи, и у меня есть такая структура:

struct EntityPersistence {
    template <typename Archive>
    void persist(Archive &ar, Entity &)
    {
    }
};

Затем в моем классе Entity у меня есть что-то вроде этого:

static const EntityPersistence entityPersistence;

PERSISTENCE_CUSTOM(Entity, entityPersistence)

Этот макрос делает что-то вроде этого:

#define PERSISTENCE_CUSTOM(Base, customPersistence)  \
SERIALIZE(Base, customPersistence)

Следуя цепочке ... (вот где важная вещь)

#define SERIALIZE(Base, customPersistence)
template <class Archive>
void serialize(Archive& ar)
{
    serialize_custom(ar);
}

template <class Archive, class Base, decltype(customPersistence) &persistence = customPersistence>
std::enable_if_t<std::is_base_of<cereal::InputArchive<Archive>, Archive>::value && has_deserialize<std::remove_const<decltype(customPersistence)>::type, Archive&, Base&>() == true, void>
serialize_custom(Archive &ar)
{
    persistence.deserialize(ar, const_cast<Base&>(*this));                                    
}

Некоторый недостающий код для проверки, какие функции реализованы вструктура Persistance для ветвления кода выполнения во время компиляции:

template<class> struct sfinae_true : std::true_type{};

template<class T, class A0, class A1>
static auto test_deserialize(int)
-> sfinae_true<decltype(std::declval<T>().deserialize(std::declval<A0>(), std::declval<A1>()))>;
template<class, class A0, class A1>
static auto test_deserialize(long) -> std::false_type;

template<class T, class A0, class A1>
static auto test_persist(int)
-> sfinae_true<decltype(std::declval<T>().persist(std::declval<A0>(), std::declval<A1>()))>;
template<class, class A0, class A1>
static auto test_persist(long) -> std::false_type;

template<class T, class Arg1, class Arg2>
struct has_deserialize : decltype(::detail::test_deserialize<T, Arg1, Arg2>(0)){};
template<class T, class Arg1, class Arg2>
struct has_persist : decltype(::detail::test_persist<T, Arg1, Arg2>(0)){};

Обсуждаемая ошибка:

In member function ‘std::enable_if_t<(std::is_base_of<cereal::InputArchive<Archive>, Archive>::value && (has_deserialize<EntityPersistence, Archive&, Entity&>() == true)), void> Entity::serialize_custom(Archive&)’:
error: ‘const struct EntityPersistence’ has no member named ‘deserialize’
     persistence.deserialize(ar, const_cast<Base&>(*this));                                    \
                 ^

deserialize функция не существует в EntityPersistence, но эта serialize_custom специализация не должна также, если бы enable_if_t сделал бы свою работу.Я протестировал has_deserialize структуру вне этого кода, и она отлично работает.Может ли это быть как-то связано с нетипичным параметром шаблона в функциях serialize_custom?Может быть, он оценивается до enable_if_t?

Заранее спасибо

Ответы [ 2 ]

0 голосов
/ 11 февраля 2019

Я наконец решил эту проблему с помощью промежуточного метода (на случай, если кому-то интересно):

template <class Archive>
void serialize(Archive& ar)
{
    serialize_custom_helper(ar);
}

template <class Archive, decltype(customPersistence)& persistence = customPersistence>        \
void serialize_custom_helper(Archive& ar)
{
    serialize_custom(ar, persistence);
}

template <class Archive, class Base, class P>
std::enable_if_t<std::is_base_of<cereal::InputArchive<Archive>, Archive>::value && has_deserialize2<P, Archive&, Base&>() == true, void> 
serialize_custom(Archive &ar, P& persistence)
{
    persistence.deserialize(ar, const_cast<Base&>(*this));
}

...
0 голосов
/ 08 февраля 2019

Не уверен, и у меня достаточно элемента, чтобы попробовать, но ... как насчет проверки persistence (параметр шаблона serialize_custom()) вместо customPersistence (это не параметр шаблона serialize_custom()?

Я имею в виду ... как насчет следующего?

template <class Archive, class Base,
          decltype(customPersistence) & persistence = customPersistence>
std::enable_if_t<std::is_base_of<cereal::InputArchive<Archive>, Archive>::value                   
              && has_deserialize<std::remove_const<decltype(persistence)>::type,
                              Archive&, Base&>() == true> //^^^^^^^^^^^
serialize_custom(Archive &ar)
{
    persistence.deserialize(ar, const_cast<Base&>(*this));                                    
}
...