19

The following code:

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

Fails to compile with the error:

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

If I change it to:

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

I get another error:

error: invalid use of 'this' at top level

What is wrong with either of these? I am using gcc 4.6

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
HighCommander4
  • 50,428
  • 24
  • 122
  • 194

6 Answers6

14

Here are the magic words:

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

Edit I see from Mikael Persson's answer that this is how it's done in boost.

TonyK
  • 16,761
  • 4
  • 37
  • 72
7

result_of and decltype in combination can give the the return type for a member function

#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;
}
Kjell Hedström
  • 470
  • 5
  • 11
  • I put up a [blog entry](http://kjellkod.wordpress.com/2014/04/30/c11-template-tricks-finding-the-return-value-type-for-member-function/) where different use cases can be seen for when this is helpful. – Kjell Hedström May 01 '14 at 03:51
7

Currently you can only access 'this' and members of the class inside the function body, but this is likely to be changed soon:

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1207

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
5

Comeau doesn't like auto as a top level return type, but the following compiles successfully:

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);
};

Basically, you have to declare at least one additional construct that gets you the type you want. And use decltype directly.

EDIT: Incidentally, this works fine for diving into the return type of a member function as well:

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);
}

Granted, it doesn't have the same convenience of auto f()-> ..., but at least it compiles.

MSN
  • 53,214
  • 7
  • 75
  • 105
  • Also, this doesn't work if f is a template member function unless you select the correct overload explicitly, which makes it even more verbose – HighCommander4 Feb 28 '11 at 22:53
  • @HighCommander4 Are you asking if there is a less ugly way to do this? I think the answer is no, for the very reasons you bring up. – MSN Feb 28 '11 at 23:36
3

After some tests, neither decltype(declval<A>().f(x)) nor decltype(((A*)0)->f(x)) will work.

However, it seems that using boost::bind will work (and it's "under-the-hood" version):

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.
};

Of course, this is not pretty. I guess you can look into how boost::bind does it to maybe find a nicer solution.

EDIT

As MSN suggested, you can also make your own function template to resolve this:

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));
};
Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
0

Seems to me that does not work because the decltype is outside of the method and A is at that moment an incomplete type (so you can't even do A().f(x)).

But you should not really need that. Outside of the declaration of A this will work as expected, in A you should know the return type of the function that you declared a few lines above. Or you could just write:

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

This even works with plain c++03.

Fozi
  • 4,973
  • 1
  • 32
  • 56
  • The example I gave is obviously simplified to highlight the problem. In my actual code, the return type of f is not "int", but some complicated expression involving Boost.Range transformations, bind-expressions, and so on (in fact, f itself uses decltype to declare its return type). – HighCommander4 Feb 28 '11 at 22:35
  • @HighCommander: So you manage to declare the return value once but not the second time? – UncleBens Feb 28 '11 at 23:27
  • @UncleBens: No, not even once. As I said, f itself uses decltype to declare its return type. – HighCommander4 Mar 01 '11 at 07:44
  • Did you try `typedef decltype(...) ret_type;`? – Fozi Mar 01 '11 at 17:31
  • Yes, it has the same problem. – HighCommander4 Mar 01 '11 at 20:52
  • But in `(...)` you have to put whatever you put in `f` to declare the return type, not what you wrote in the question. – Fozi Mar 03 '11 at 20:06