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

Редактиране: Отговорът, който маркирах по-долу, не е 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>() е xvalue. & може да се използва само за lvalues.   -  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
@T.C. По дяволите, мразя този глупав език. Ти давай: ще оставя глупавия си хак :P - person Lightness Races in Orbit; 17.06.2015