SFINAE для методов класса - PullRequest
0 голосов
/ 01 июня 2018

В статьях https://www.fluentcpp.com/2018/05/15/make-sfinae-pretty-1-what-value-sfinae-brings-to-code/ и https://www.fluentcpp.com/2018/05/18/make-sfinae-pretty-2-hidden-beauty-sfinae/ объясняется, как использовать SFINAE для методов класса.Первая реализация класса выглядит следующим образом:

template<typename T>
class MyClass
{
public:
    void f(T const& x);
    void f(T&& x);
};

Для предотвращения использования второй функции f, если T является ссылкой, в статье представлено следующее решение:

template<typename T>
class MyClass
{
public:
    void f(T const&  x){}

    template<typename T_ = T, typename = std::enable_if_t<!std::is_reference_v<T_>>>
    void f(T&& x){}
};

Разве не было бы проще / чище заменить тип возврата метода на std::enable_if?Таким образом, класс будет выглядеть следующим образом:

template<typename T>
class MyClass
{
public:
    void f(T const&  x){}

    std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}
};

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Разве не было бы проще / чище заменить тип возврата метода enable_if?

Полагаю, это вопрос личного вкуса.

В любом случае, примите во внимание, что ваш пример

std::enable_if_t<!std::is_reference_v<T>>> f(T&& x){}

не работает, потому что SFINAE работает над шаблонамиконкретный метод.Итак, для вашего примера вы должны использовать шаблонный тип T_ (позвольте мне его назвать U), а условие std::is_reference должно оценивать U, а не T

template <typename U = T>
std::enable_if_t<!std::is_reference_v<U>> f(T&& x){}

В любом случае, для обоих решений существует риск «угона»: вы можете обойти тест, объяснив тип U

myClassObject.template f<void>(aReference);

Чтобы избежать риска перехвата, вы должны также наложить T иU одного типа

template<typename U = T,
         typename = std::enable_if_t<
            !std::is_reference_v<U>
            && std::is_same_v<U, T>>>
void f(T&& x){}

template <typename U = T>
std::enable_if_t<
   !std::is_reference_v<U>
   && std::is_same_v<U, T>> f(T&& x)
 { }
0 голосов
/ 01 июня 2018

Во-первых, ваша техника не работает.T является фиксированным типом, в то время как MyClass enable_if_t<false> плохо сформирован.Подстановка не выполняется, так что это не сбой подстановки, это просто неправильно сформированная подпись.

Вы можете исправить это до некоторой степени с помощью

template<class T_=T>
std::enable_if_t<!std::is_reference_v<T_>>> f(T_&& x){}

Теперь эта техника(использование возвращаемого значения) не работает (A) для конструкторов и (B), когда вы хотите определить тип возвращаемого значения.

Также смешивает тип возвращаемого значения с кодом SFINAE;эти два не имеют ничего общего друг с другом.

Вдобавок ко всему, и эта техника, и оригинал, который вы копируете, имеют некоторое сомнительное взаимодействие со "всеми шаблонами должны быть действительные экземпляры".Мне все еще неясно, относится ли это к каждому методу шаблона с фиксированным созданием класса шаблона или нет;если это так, то вы должны убедиться, что некоторое значение T_ сделает тело действительным.

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