На cppcon 2014 был доклад для про современное метопрограммирование шаблонов - слайды.
Там в частности рассказывалось как реализовать проверку существует ли для класса оператор копирующего присваивания. Суть метода в том, чтобы получить тип результата некоторого выражения (в данном случае оператора присваивания) через decltype, и инстанцировать этим типом шаблон. Если выражение корректно (то есть у нас есть оператор присваивания), то результатом параметризации будет один тип (например std::true_type), если нет, то другой тип (например std::false_type).
Пример кода из слайдов:
template< class T > using copy_assign_t = decltype(declval<T&>() = declval< T const& >()); template<class T> struct is_copy_assignable { private: template< class U, class = copy_assign_t<U> > static true_type try_assign( U&& ); // SFINAE may apply! static false_type try_assign(...); // catch-all overload public: using type = decltype(try_assign(declval<T>())); };
Работает это всё благодаря SFINAE.
Я попробовал написать общий класс, который возвращает true_type/false_type в зависимости от того, является ли любое переданное выражение корректным. Его можно использовать, чтобы реализовать свои проверки для типов, при этом не требуется писать много кода.
Например нужно проверить, есть ли в классе нестатическая функция get_value():
//Объявляем тип выражения template <typename T> using has_get_value_t = decltype(std::declval<T>().get_value()); template <typename T> struct has_get_value : is_correct_expression_t<T, has_get_value_t> { }; int main() { std::cout << std::is_same<std::true_type, has_get_value<MyClass>::type>::value << std::endl; }
Как это реализовано:
template <typename T, template<class> class E> struct is_correct_expression_t { private: template <typename U, typename = E<U>> static std::true_type try_evaluate(U&&); static std::false_type try_evaluate(...); public: using type = decltype(try_evaluate(std::declval<T>())); };
Для move/copy assign будет выглядеть так:
template <typename T> using copy_assign_t = decltype(std::declval<T&>() = std::declval<const T&>()); template <typename T> struct is_copy_assignable : is_correct_expression_t<T, copy_assign_t> { }; template <typename T> using move_assign_t = decltype(std::declval<T&>() = std::declval<T&&>()); template <typename T> struct is_move_assignable : is_correct_expression_t<T, move_assign_t> { };
Комментариев нет:
Отправить комментарий