Получить тип & для встроенного и оператора & ()?

Правка: ответ, который я отметил ниже, не на 100 % правильный, на самом деле он содержится в комментарии: using TPtr = decltype(&std::declval<T&>());


Я пытаюсь использовать std::conditional<>, чтобы получить тип &T, где T может иметь operator&() или нет.

Простое решение — даже не пытаться, вместо этого укажите другой аргумент шаблона:

struct Foo
{
    int operator&() { return 314; }
};

struct Bar { };

template <typename T, typename TPtr = T*>
struct A
{
    T& _t;
    A(T& t) : _t(t) {}
    TPtr data() {
        return &_t;
    }
};

где тогда код клиента

Foo foo;
A<Foo, int> aFoo(foo);
int pFooData = aFoo.data();

Bar bar;
A<Bar> aBar(bar);
Bar* pBarData = aBar.data();

Но я бы предпочел написать что-то вроде:

template <typename T>
struct B
{
    using TPtr = typename std::conditional<has_operator_address_of<T>::value, typename std::result_of<decltype(T::operator&)&()>::type, T*>::type;

    T& _t;
    B(T& t) : _t(t) {}
    TPtr data() {
        return &t;
    }
};

где has_operator_address_of создан по образцу is_call_possible. Затем код клиента

B<Foo> bFoo(foo); // no need to second template argument
pFooData = bFoo.data();

но тогда класс без operator&() не компилируется:

B<Bar> bBar(bar);
pBarData = bBar.data();

Кажется, что conditional хочет скомпилировать оба аргумента шаблона, поэтому компиляция завершается ошибкой, когда T не имеет operator&(). Я пробовал разбрызгивать std::enable_if, но безрезультатно.


person Ðаn    schedule 17.06.2015    source источник
comment
Я не понимаю, почему GCC отклоняет using TPtr = decltype(&std::declval<int>());. Я думал, что аргумент decltype должен был быть неоцененным контекстом? Просто позвольте мне использовать &, чтобы получить результирующий тип, черт возьми!   -  person Lightness Races in Orbit    schedule 17.06.2015
comment
Нет, пока я не узнаю, что это правильно. VS допускает всевозможные нестандартные вещи.   -  person Lightness Races in Orbit    schedule 17.06.2015
comment
@LightnessRacesinOrbit std::declval<int>() является значением x. & можно использовать только для lvalue.   -  person T.C.    schedule 17.06.2015


Ответы (1)


Вы можете использовать decltype и declval, применив небольшой хакерский прием, чтобы принудительно передать lvalue оператору & (что необходимо):

Начните с #include <utility> и определите следующую вспомогательную функцию:

template <typename T>
T& as_lvalue(T&& val)
{
    return val;
}

Затем:

using TPtr = decltype(&as_lvalue(std::declval<T>()));

(демонстрация)

person Lightness Races in Orbit    schedule 17.06.2015
comment
@Т.С. Черт возьми, я ненавижу этот дурацкий язык. Вы идете на это: я оставлю свой глупый взлом :P - person Lightness Races in Orbit; 17.06.2015