почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 13:46
Оценка:
привет!

подумал закодить шаблон для YAS, который будет сообщать, является ли сериализуемым какой-то конкретный тип, — но что-то SFINAE в данном случае не срабатывает, хоть и для НЕ-сериализуемого типа я получаю ошибку компиляции.

сначала минимальный пример:
    struct nonserializable_type {};

    using archive_type = yas::binary_oarchive<yas::mem_ostream>;
    yas::mem_ostream os;
    archive_type oa{os};

    nonserializable_type nst;
    oa.save(nst);

этот код не скомпилится, потому что для nonserializable_type нет сериализатора.

далее, я полагаю что могу для этого использовать SFINAE, который благополучно был найден на просторах SO:
namespace detail {

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

template<typename Ar, typename T>
static auto test_serializable(int) -> sfinae_true<decltype(std::declval<Ar>().save(std::declval<T>()))>;
template<typename Ar, typename T>
static auto test_serializable(long) -> std::false_type;

} // ns detail

template<typename Ar, typename T>
struct is_serializable: decltype(detail::test_serializable<Ar, T>(0))
{};

но в конечном счете я получаю true:
    struct nonserializable_type {};

    using archive_type = yas::binary_oarchive<yas::mem_ostream>;

    std::cout << yas::is_serializable<archive_type, nonserializable_type>::value << std::endl;

чяднт?

спасибо!
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 18.02.2020 13:53 niXman . Предыдущая версия .
Re: почему SFINAE не рабоает?
От: vopl Россия  
Дата: 18.02.20 14:24
Оценка: +1
Здравствуйте, niXman, Вы писали:

X>привет!


X>...


попробуй так

    struct nonserializable_type {};
    using archive_type = yas::binary_oarchive<yas::mem_ostream>;
    
    using ArRes = decltype(std::declval<archive_type>().save(std::declval<nonserializable_type>()));


компилируется? Если да — значит тип результата archive_type::save не зависит от состава nonserializable_type. Значит — так ты не сможешь определить, будет ли компилироваться тело save. Другими словами — если результирующий тип save известен компилятору без учета типа аргумента — то нет никакого "substitution failure" (ведь подстановка прошла удачно), соответственно, ты получаешь true_type в своем тесте.

А далее (вне твоего определятора, потом-потом...) уже компилятор инстанцирует save типом nonserializable_type, начинает его компилировать и натыкается на ошибки.
Re: почему SFINAE не рабоает?
От: rg45 СССР  
Дата: 18.02.20 14:28
Оценка:
Здравствуйте, niXman, Вы писали:

X>привет!


X>подумал закодить шаблон для YAS, который будет сообщать, является ли сериализуемым какой-то конкретный тип, — но что-то SFINAE в данном случае не срабатывает, хоть и для НЕ-сериализуемого типа я получаю ошибку компиляции.


X>далее, я полагаю что могу для этого использовать SFINAE, который благополучно был найден на просторах SO:

X>
X>namespace detail {

X>template<typename>
X>struct sfinae_true: std::true_type{};

X>template<typename Ar, typename T>
X>static auto test_serializable(int) -> sfinae_true<decltype(std::declval<Ar>().save(std::declval<T>()))>;
X>template<typename Ar, typename T>
X>static auto test_serializable(long) -> std::false_type;

X>} // ns detail

X>template<typename Ar, typename T>
X>struct is_serializable: decltype(detail::test_serializable<Ar, T>(0))
X>{};

X>

X>но в конечном счете я получаю true:
X>чяднт?

Трудно делать диагностику, не видя всего кода. И реализация is_serializable стремная — у тебя две независимые перегрузки, причем вторая полностью перекрывает первую. Х.з. что там пошло не так, но я бы так делать не стал. А попробуй-ка вот такой вариант:

template<typename Ar, typename T, typename = void>
struct is_serializable : std::false_type {};

template<typename Ar, typename T>
struct is_serializable<Ar, T, std::void_t<decltype(std::declval<Ar&>().save(std::declval<T>()))>> : std::true_type {};
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 18.02.2020 14:36 rg45 . Предыдущая версия .
Re[2]: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 14:33
Оценка:
Здравствуйте, vopl, Вы писали:

V> компилируется? Если да — значит тип результата archive_type::save не зависит от состава nonserializable_type.


думаю, ты ошибаешься... или я...

тут:
template<typename>
struct sfinae_true: std::true_type{};

template<typename Ar, typename T>
static auto test_serializable(int) -> sfinae_true<decltype(std::declval<Ar>().save(std::declval<T>()))>;

— не важно какой тип вернет decltype(), важно лишь — чтоб expression был валидным...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 18.02.2020 14:40 niXman . Предыдущая версия .
Re[2]: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 14:40
Оценка:
Здравствуйте, rg45, Вы писали:

R>Здравствуйте, niXman, Вы писали:


X>>привет!


R> ... А попробуй-ка вот такой вариант:


тоже true
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 18.02.2020 14:41 niXman . Предыдущая версия .
Re[3]: почему SFINAE не рабоает?
От: vopl Россия  
Дата: 18.02.20 14:41
Оценка:
Здравствуйте, niXman, Вы писали:

X>Здравствуйте, vopl, Вы писали:


V>> компилируется? Если да — значит тип результата archive_type::save не зависит от состава nonserializable_type.


X>думаю, ты ошибаешься... или я...


X>тут:

X>
X>template<typename>
X>struct sfinae_true: std::true_type{};

X>template<typename Ar, typename T>
X>static auto test_serializable(int) -> sfinae_true<decltype(std::declval<Ar>().save(std::declval<T>()))>;
X>

X>- не важно какой- тип вернет decltype(), важно лишь — чтоб expression был валидным...

компилятор этот expression не разворачивает и внутрь него не заглядывает... Вот посмотри сюда https://gcc.godbolt.org/z/UhGLUf — там тело save вообще не задано
Отредактировано 18.02.2020 14:41 vopl . Предыдущая версия .
Re[3]: почему SFINAE не рабоает?
От: rg45 СССР  
Дата: 18.02.20 14:43
Оценка:
Здравствуйте, niXman, Вы писали:

R>> ... А попробуй-ка вот такой вариант:


X>тоже true


Значит, нужно смотреть, что там у тебя в binary_oarchive. Ты уверен, что у тебя там нет какой-нибудь всеядной save?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[4]: почему SFINAE не рабоает?
От: vopl Россия  
Дата: 18.02.20 14:45
Оценка:
Здравствуйте, vopl, Вы писали:

V>Здравствуйте, niXman, Вы писали:


X>>Здравствуйте, vopl, Вы писали:


V>>> компилируется? Если да — значит тип результата archive_type::save не зависит от состава nonserializable_type.


X>>думаю, ты ошибаешься... или я...


X>>тут:

X>>
X>>template<typename>
X>>struct sfinae_true: std::true_type{};

X>>template<typename Ar, typename T>
X>>static auto test_serializable(int) -> sfinae_true<decltype(std::declval<Ar>().save(std::declval<T>()))>;
X>>

X>>- не важно какой- тип вернет decltype(), важно лишь — чтоб expression был валидным...

V>компилятор этот expression не разворачивает и внутрь него не заглядывает... Вот посмотри сюда https://gcc.godbolt.org/z/UhGLUf — там тело save вообще не задано


плоховатый пример привел, вот поближе к твоему случаю https://gcc.godbolt.org/z/duoD6V
Re[4]: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 14:48
Оценка:
Здравствуйте, rg45, Вы писали:

R> ... Ты уверен, что у тебя там нет какой-нибудь всеядной save?


если бы она была, код бы компилился успешно?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[5]: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 14:52
Оценка:
Здравствуйте, vopl, Вы писали:

V>плоховатый пример привел, вот поближе к твоему случаю https://gcc.godbolt.org/z/duoD6V


похоже ты прав...
хм...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 14:55
Оценка:
вот сообщение компилятора об ошибке компиляции:
/home/nixman/yas/tests/base/../../include/yas/binary_oarchive.hpp:89:16: error: incomplete type ‘yas::detail::serializer<(yas::detail::type_prop)4, (yas::detail::ser_case)4, 65, nonserializable_type>’ used in nested name specifier
         return serializer<
                ~~~~~~~~~~~
              detail::type_properties<T>::value
              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
             ,detail::serialization_method<T, this_type>::value
             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
             ,F
             ~~  
             ,T
             ~~  
         >::save(*this, v);
         ~~~~~~~^~~~~~~~~~


где yas::detail::serializer — это набор собственно сериализаторов, типа этого:
https://github.com/niXman/yas/blob/master/include/yas/types/std/chrono.hpp
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 18.02.2020 14:57 niXman . Предыдущая версия .
Re[5]: почему SFINAE не рабоает?
От: rg45 СССР  
Дата: 18.02.20 14:55
Оценка:
Здравствуйте, niXman, Вы писали:

R>> ... Ты уверен, что у тебя там нет какой-нибудь всеядной save?


X>если бы она была, код бы компилился успешно?


Ну это смотря какой код. И смотря как объявлены эти save. Своему варианту is_seralizable я доверяю, и он говорит, что какой-то save у тебя там находится, все-таки. Попробуй на место архива подставить какой-нибудь другой тип и убедишься, что он просто так 'true' не выдает.
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[6]: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 15:00
Оценка:
Здравствуйте, rg45, Вы писали:

R>... Попробуй на место архива подставить какой-нибудь другой тип и убедишься, что он просто так 'true' не выдает.


это я уже проверил — все рааботает.

просто, похоже, vopl — прав: компилятор просто видит что у архива есть метод save(T) да еще и шаблонный — и он считвает что все ОК...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[7]: почему SFINAE не рабоает?
От: rg45 СССР  
Дата: 18.02.20 15:05
Оценка: +1
Здравствуйте, niXman, Вы писали:

X>просто, похоже, vopl — прав: компилятор просто видит что у архива есть метод save(T) да еще и шаблонный — и он считвает что все ОК...


Так и я высказывал это же предположение. Не лучше ли тебе в таком случае проверять наличие методов у сериализуемых объектов, а не у архива?
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[8]: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 15:12
Оценка:
Здравствуйте, rg45, Вы писали:

R>... Не лучше ли тебе в таком случае проверять наличие методов у сериализуемых объектов, а не у архива?

тут несколько неудобных моментов:
1)сериализация/десериализация может использовать как методы объектов, так и free-функции. но это не самое сложное.
2)фундаментальные типы не имеют ни того, ни другого. они сериализуются "внутри".
3)YAS поддерживает множество типов "изкоробки", типа строк, векторов, етц...

т.е. мне нужно проверять именно наличие serializer<>::save(T)... думаю...
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Отредактировано 18.02.2020 15:13 niXman . Предыдущая версия .
Re[9]: почему SFINAE не рабоает?
От: rg45 СССР  
Дата: 18.02.20 15:30
Оценка: +1
Здравствуйте, niXman, Вы писали:

X>т.е. мне нужно проверять именно наличие serializer<>::save(T)... думаю...


Можно проверять наличие свободной функции (save) для пары типов. И продоставить дженериковую версию такой функции с использованием SFINAE:

template <typename Ar, typename T>
auto save(Ar& ar, const T& t) -> decltype(std::declval<T>().save(std::declval<Ar&>()))
{
   return t.save(ar);
}


Таким образом ты получаешь возможность реализовывать кастомную сериализацию либо как функцию-член, либо как свободную функцию. А с шаблонными функциями нужно быть поосторожнее в таких случаях. Их всеядность следует ограничивать, при помощи SFINAE.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 18.02.2020 15:37 rg45 . Предыдущая версия . Еще …
Отредактировано 18.02.2020 15:34 rg45 . Предыдущая версия .
Re: почему SFINAE не рабоает?
От: niXman Ниоткуда https://github.com/niXman
Дата: 18.02.20 17:41
Оценка: +1
вопрос был решен таким способом:
namespace detail {

template<typename...>
using void_t = void;

} // ns detail

template<typename Ar, typename T, typename = void>
struct is_serializable : std::false_type {};

template<typename Ar, typename T>
struct is_serializable<Ar, T, detail::void_t<decltype(
    detail::serializer<
         detail::type_properties<T>::value
        ,detail::serialization_method<T, Ar>::value
        ,Ar::flags()
        ,T
    >::save(std::declval<Ar &>(), std::declval<T>()))>> : std::true_type
{};

https://github.com/niXman/yas/blob/master/include/yas/detail/type_traits/type_traits.hpp#L314

rg45, спасибо!
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.