Вопрос по visual-c++, c++, c++11 – SFINAE - Попытка определить, имеет ли тип шаблона функцию-член с возвращаемым типом 'variable'

5

Возникли проблемы с SFINAE. Мне нужно иметь возможность определить, есть ли у Type функция-член operator- & gt; определяется независимо от его типа возврата. Пример следует.

Этот класс в тестере. Он определяет operator- & gt; () с типом возврата X *. Таким образом, я не буду знать, что такое «X»; это жестко закодировать это везде.

<code>template <class X>
class PointerX
{
    ...

    X* operator->() const;
    ...
}
</code>

Этот класс пытается определить, имеет ли переданный в T метод operator- & gt; определены; независимо от того, какой оператор & gt; тип возвращаемого значения.

<code>template<typename T>
struct HasOperatorMemberAccessor
{
    template <typename R, typename C> static R GetReturnType( R ( C::*)()const);

    template<typename U, typename R, R(U::*)()const> struct SFINAE{};
    template<typename U> static char Test(SFINAE<U,     decltype( GetReturnType(&U::operator->)),   &U::operator-> >*);
    template<typename U> static uint Test(...);
    static const bool value = sizeof(Test<T>(0)) == sizeof(char);
};
</code>

Этот класс точно такой же, как указано выше, за исключением того, что operator- & gt; тип возвращаемого значения должен быть «объект».

<code>template<typename T>
struct HasOperatorMemberAccessorOBJECT
{
    template <typename R, typename C> static R GetReturnType( R ( C::*)()const);

    template<typename U, typename R, R(U::*)()const> struct SFINAE{};
    template<typename U> static char Test(SFINAE<U,     Object*,                &U::operator-> >*); // only change is we hardcoded Object as return type.
    template<typename U> static uint Test(...);
    static const bool value = sizeof(Test<T>(0)) == sizeof(char);
};
</code>

Результаты:

<code>void main()
{
    HasOperatorMemberAccessor<PointerX<Object>>::Test<PointerX<Object>>(0);         // fails  ::value is false;  Test => Test(...)

    HasOperatorMemberAccessorOBJECT<PointerX<Object>>::Test<PointerX<Object>>(0);       // works! ::value is true;   Test => Test(SFINAE<>*)  
}
</code>

HasOperatorMemberAccessor не смог найти функцию-член PointX «Оператор объекта- () const». Таким образом, он использует универсальную версию Test (...).

Однако HasOperatorMemberAccessorOBJECT смог найти PointX's Object operator- & gt; () const ". Таким образом, он использует специализированную версию Test (SFINAE *).

Оба должны были найти «Оператор объекта» () const & quot; Способ; и, таким образом, оба должны использовать специализированную версию Test (SFINAE *); и, таким образом, HasOperatorMemberAccessor & gt; :: value должен быть истинным для обоих.

Единственное различие между HasOperatorMemberAccessor и HasOperatorMemberAccessorOBJECT заключается в том, что HasOperatorMemberAccessorOBJECT имеет типовое имя R, жестко закодированное для объекта,

Таким образом, проблема заключается в том, что & quot; decltype (GetReturnType (& amp; U :: operator- & gt;)) & quot; не возвращает объект правильно. Я пробовал несколько разных разрешений на обнаружение возвращаемого типа. Они идут следующим образом:

<code>    decltype( GetReturnType(&U::operator->) )
    typename decltype( GetReturnType(&U::operator->))
    decltype( ((U*)nullptr)->operator->() )
    typename decltype( ((U*)nullptr)->operator->() )
</code>

Нет работы, почему? Я использую MSVC ++ 10.0.

Одна вещь, которая бросается в глаза, это то, чтоPointerX<bool>::operator-> возвращаетсяbool*неbool. n.m.
Дай мне попробовать снова.PointerX<Object>::operator-> возвращаетсяObject*. decltype(...) было быObject*. HasOperatorMemberAccessorOBJECT казалось бы, удается, хотя он заменяетdecltype(...)  сObject, Похоже, что-то здесь не так. Я не говорю оHasOperatorMemberAccessor совсем. n.m.
Тип X в PointerX не имеет значения в отношении HasOperatorMemberAccessor. Я попытался обобщить мою проблему, не добавляя в пример много посторонних объектов. Если это слишком запутанно, я заменю bool на string. Michael G

Ваш Ответ

1   ответ
4

decltype ведет себя не так, как вы ожидаете? Если первое, вот один подход:

#include <type_traits>

template<typename T, bool DisableB = std::is_fundamental<T>::value>
struct HasOperatorMemberAccessor
{ 
private:
    typedef char no;
    struct yes { no m[2]; };

    struct ambiguator { char* operator ->() { return nullptr; } };
    struct combined : T, ambiguator { };
    static combined* make();

    template<typename U, U> struct check_impl;
    template<typename U>
    static no check(
        U*,
        check_impl<char* (ambiguator::*)(), &U::operator ->>* = nullptr
    );
    static yes check(...);

public:
    static bool const value=std::is_same<decltype(check(make())), yes>::value;
};

// false for fundamental types, else the definition of combined will fail
template<typename T>
struct HasOperatorMemberAccessor<T, true> : std::false_type { };

// true for non-void pointers
template<typename T>
struct HasOperatorMemberAccessor<T*, false> :
    std::integral_constant<
        bool,
        !std::is_same<typename std::remove_cv<T>::type, void>::value
    >
{ };

template<typename X>
struct PointerX
{
    X* operator ->() const { return nullptr; }
};

struct X { };

int main()
{
    static_assert(
        HasOperatorMemberAccessor<PointerX<bool>>::value,
        "PointerX<> has operator->"
    );
    static_assert(
        !HasOperatorMemberAccessor<X>::value,
        "X has no operator->"
    );
    static_assert(
        HasOperatorMemberAccessor<int*>::value,
        "int* is dereferencable"
    );
    static_assert(
        !HasOperatorMemberAccessor<int>::value,
        "int is not dereferencable"
    );
    static_assert(
        !HasOperatorMemberAccessor<void*>::value,
        "void* is not dereferencable"
    );
}

В VC ++ 2010 отсутствуют необходимые средства C ++ 11 (например, выражение SFINAE), необходимые для того, чтобы сделать это намного чище.

Error: User Rate Limit Exceededstd::is_same + decltypeError: User Rate Limit ExceededsizeofError: User Rate Limit Exceeded
decltypeError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Michael G
Error: User Rate Limit Exceededvoid*Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededHasOperatorMemberAccessor<>Error: User Rate Limit Exceededtemplate<typename T> class HasOperatorMemberAccessor<T*> : public std::true_type { };Error: User Rate Limit ExceededdecltypeError: User Rate Limit ExceededdecltypeError: User Rate Limit Exceeded

Похожие вопросы