Как обеспечить приемлемый тип шаблона C ++ для перегрузки оператора? - PullRequest
0 голосов
/ 18 октября 2018

Я хочу реализовать шаблон класса:

template <typename Type>
class MyClass {/*...*/}

Я хочу заставить Type, принятый MyClass, перегрузить оператор <.Как я могу это сделать?Это должно быть возможно, потому что стандартная библиотека делает это для отсортированных контейнеров.Я не хочу использовать явную специализацию шаблонов и реализовать в MyClass для определенных типов.Я хочу, чтобы за это ответила Type.

Ответы [ 3 ]

0 голосов
/ 18 октября 2018

Самый простой способ - просто использовать его.Шаблоны C ++ полностью утка и не очень проверены, пока вы не передадите фактический тип.

Вы можете использовать методы, основанные на SFINAE, для тестирования подобных вещей ...

namespace details {
  template<template<class...>class Z, class, class...>
  struct can_apply:std::false_type{};
  template<class...>struct voider {using type=void;};
  template<class...Ts>using void_t=typename voider<Ts...>::type;
  template<template<class...>class Z, class...Ts>
  struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
}
template<template<class...>class Z, class...Ts>
using can_apply = details::can_apply<Z,void,Ts...>;

этопомощник SFINAE, который определяет, можете ли вы применить шаблон к пачке типов.

template<class X, class Y=X>
using raw_less_r = decltype( std::declval<X>()<std::declval<Y>() );

template<class X, class Y=X>
using can_raw_less = can_apply<raw_less_r, X, Y>;

и теперь can_raw_less<int> является производным от true_type, если int < int допустим, и false_type в противном случае.

Затем мы уходим и:

template <typename Type, class=void>
class MyClass;

template <typename Type>
class MyClass<Type, std::enable_if_t<can_raw_less<Type>>>
{/*...*/}

используем SFINAE и enable_if_t, чтобы создать специализацию, которая существует тогда и только тогда, когда Type<Type действителен.

Примечаниечто лучший шаблон, вероятно, выглядит так:

template<class F, class...Args>
using invoke_result = decltype( std::declval<F>()( std::declval<Args>()... ) );
template<class F, class...Args>
using can_invoke = can_apply< invoke_result, F, Args... >;

template<class Type, class Cmp=std::less<Type>>
class MyClass {
  static_assert( can_invoke< Cmp, Type const&, Type const& >{}, "You must be able to compare Type to itself" );
  // use Cmp{}(Type, Type) to compare
};

, что и делают контейнеры std, с добавлением static_assert для более чистых сообщений об ошибках.

0 голосов
/ 18 октября 2018

Простой и читаемый, используя boost :: has_less из Boost.TypeTraits :

#include <boost/type_traits/has_less.hpp>

template <typename Type>
class MyClass {
    static_assert( boost::has_less<Type>::value, 
                   "Template parameter Type must be less-than-comparable" );  
};

Live Demo

0 голосов
/ 18 октября 2018

Если реализация MyClass использует оператор < для объектов Type, вам не нужно ничего делать.Компилятор сообщит об ошибке, если операция не поддерживается.

Если реализация MyClass не использует оператор < для объектов Type, то беспокоиться не о чем.

В любом случае вам нечего делать, кроме документирования того, что ожидается от Type.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...