Вызов функции-члена в decltype - PullRequest
16 голосов
/ 28 февраля 2011

следующий код:

struct A
{
    int f(int);
    auto g(int x) -> decltype(f(x));
};

Не компилируется с ошибкой:

error: cannot call member function 'int B::f(int)' without object

Если я изменю его на:

struct A
{
    int f(int);
    auto g(int x) -> decltype(this->f(x));
};

Я получаю еще одну ошибку:

error: invalid use of 'this' at top level

Что не так с любым из них? Я использую gcc 4.6

Ответы [ 6 ]

11 голосов
/ 01 марта 2011

Вот волшебные слова:

struct A
{
    int f(int);
    auto g(int x) -> decltype((((A*)0) ->* &A::f)(x)) ;
};

Редактировать Я вижу из ответа Микаэля Перссона, как это происходит в бусте.

7 голосов
/ 01 мая 2014

result_of и decltype в комбинации могут дать тип возврата для функции-члена

#include <type_traits>
using namespace std;

struct A
{
    int f(int i) { return i; } 
    auto g(int x) -> std::result_of<decltype(&A::f)(A, int)>::type
    { 
        return x;
    }
};


int main() {
    A a;
static_assert(std::is_same<decltype(a.f(123)), 
                  decltype(a.g(123))>::value, 
                  "should be identical");
return 0;
}
6 голосов
/ 01 марта 2011

В настоящее время вы можете получить доступ только к 'this' и членам класса внутри тела функции, но, скорее всего, это скоро изменится:

http://www.open -std.org / ОТК1 / SC22 / wg21 / документы / cwg_defects.html # 1207

5 голосов
/ 01 марта 2011

Comeau не нравится auto как тип возвращаемого значения верхнего уровня, но следующие успешно компилируются:

template <typename R, typename C, typename A1> R get_return_type(R (C::*)(A1));

struct A
{
    int f(int);
    decltype(get_return_type(&A::f)) g(int x);
};

По сути, вы должны объявить хотя бы одну дополнительную конструкциюэто дает вам тот тип, который вы хотите.И используйте decltype напрямую.

РЕДАКТИРОВАТЬ: Между прочим, это прекрасно работает для погружения в возвращаемый тип функции-члена:

template <typename R, typename C, typename A1> R get_return_type(R (C::*)(A1));

struct B { int f(int); };

struct A
{
    int f(int);
    B h(int);

    decltype(get_return_type(&A::f)) g(int x);

    decltype(get_return_type(&A::h).f(0)) k(int x);
};

int main()
{
    return A().k(0);
}

Конечно, он не имеетто же удобство auto f()-> ..., но, по крайней мере, компилируется.

3 голосов
/ 01 марта 2011

После некоторых тестов ни decltype(declval<A>().f(x)), ни decltype(((A*)0)->f(x)) работать не будут.

Однако, похоже, что работает boost :: bind (и это версия "под капотом"):

struct A
{
    int f(int);
    auto g(int x) -> decltype(boost::bind(&A::f,0,x)());
    auto h(int x) -> decltype((((A*)0)->*(&A::f))(x)); //similarly (what Boost.Bind does under-the-hood.
};

Конечно, это не красиво.Я думаю, вы можете посмотреть, как boost :: bind делает это, чтобы найти более удачное решение.

EDIT

Как и предлагал MSN, вы также можете создать свою собственную функциюшаблон для решения этой проблемы:

template< typename R, typename C, typename... Args > R member_func(R (C::*)(Args...)); 

struct A
{
    int f(int);
    auto g(int x) -> decltype(member_func(&A::f));
};
0 голосов
/ 01 марта 2011

Мне кажется, что это не работает, потому что тип decl находится за пределами метода, и в этот момент A является неполным типом (так что вы даже не можете сделать A().f(x)).

Но тебе это не нужно. Вне объявления A это будет работать как положено, в A вы должны знать тип возврата функции, которую вы объявили несколькими строками выше. Или вы можете просто написать:

struct A {
    typedef int ret_type;
    ret_type f(int x);
    ret_type g(int x);
};

Это работает даже с простым c ++ 03.

...