Decltype as a Return Type in Class Member Function

Get return type of member function without an object

You don't need that- remember that since decltype doesn't evaluate its argument, you can just call on nullptr.

decltype(((T*)nullptr)->foo()) footype;

decltype as a return type in class member function

The definition of the class is processed it two passes: first the member declarations are collected, including function signatures, and then the bodies of definitions are parsed.

The function body therefore has access to all member declarations, including subsequent ones, but the function prototype only sees preceding declarations.

How to get the return type of a member function from within a class?

g++4.9 issues the same error

I'm not sure if this is an invalid code, because incomplete types are allowed for declval, and expression in decltype is not evaluated.
rightføld in his answer explained very good why this code is invalid.

You can use std::result_of:

using bar_type = std::result_of<decltype(&foo::bar)(foo)>::type;

Which is actually implemented like this:

using bar_type = decltype((std::declval<foo>().*std::declval<decltype(&foo::bar)>())());

The difference between this and the code in the question is that pointer-to-member operator (.*) is used instead of member access operator (.), and it doesn't require the type to be complete, which is demonstrated by this code:

#include <utility>
struct foo;
int main() {
int (foo::*pbar)();
using bar_type = decltype((std::declval<foo>().*pbar)());
}

Deduce return type of member function

Is this close to what you wanted?

#include <vector>
#include <utility>
#include <memory>

struct Foo
{
int member_func();
};

template <typename Vec>
void func(const Vec& vec) {

using ret_type = decltype(std::declval<typename Vec::value_type>()->member_func());

std::vector< ret_type > local_vec;
}

int main()
{
std::vector<std::unique_ptr<Foo>> v;
func(v);
}

Demo: https://godbolt.org/g/dJkSf1

Explanation:

std::declval<typename Vec::value_type>() generates a reference to a unique_ptr (which must be used in an unevaluated context). We then take the decltype of calling generated_reference->member_function().

This would be the same type as the result of vec[0]->member_func()

Indeed, we could write it this way:

template <typename Vec>
void func(const Vec& vec) {

using ret_type = decltype(vec.at(0)->member_func());

std::vector< ret_type > local_vec;
}

Which might be more expressive and generic (Vec may now be any type which is vector-like and holds pointer-like things to Foo)

Furthermore, the more generically we approach the deduction, the more generic our func function becomes:

#include <vector>
#include <utility>
#include <memory>
#include <set>
#include <iterator>

struct Foo
{
int member_func();
};

template <typename Vec>
void func(const Vec& vec) {

using ret_type = decltype((*std::begin(vec))->member_func());

std::vector< ret_type > local_vec;
}

int main()
{
std::vector<std::unique_ptr<Foo>> v;
func(v);
func(std::array<std::unique_ptr<Foo>, 10> { });

Foo* foos[] = { nullptr, nullptr };
func(foos);

func(std::set<std::shared_ptr<Foo>, std::owner_less<>> {});
}

Note

This code assumes that the return_type of Foo::member_func is not a reference type.

If that's a possibility, we'd need to decide whether we used metaprogramming to:

a) convert reference types to std::reference_wrapper, so they can be stored in a vector, or

b) convert reference types to fundamental types using std::decay, which would result in copies being made.

Get the size of the return type of a member function

invoke_result is defined as:

template< class F, class... ArgTypes>
class invoke_result;

Hence, this is working

return sizeof(std::invoke_result_t<decltype(&QString::ucs2), QString>);

std::bind works with decltype type of class member functions failed

There are a number of issues with your last std::bind call:

  • std::remove_pointer(result3)

remove_pointer is a class. You want remove_pointer_t which will produce the type sans pointer in parentheses, which leads to the next point

  • result3 is an instance of Result*, we need to use decltype to get its type, because remove_pointer operates on type, which leads to the next point:

  • std::remove_pointer as a templated type trait wants a type as a template argument in angle braces, not in parentheses

With the edits applied this bring us to the following syntax

MyGet mg3 = std::bind(&std::remove_pointer_t<decltype(result3)>::get, result3, std::cref("result3"));

Demo


In the end, a lambda may be easier to deal with. You don't need to construct a std::function at all:

Result result1;
auto mg1 = [&result1](){return result1.get("result1");};
std::cout << mg1() << std::endl;
Result result2;
auto mg2 = [&result2](){return result2.get("result2");};
std::cout << mg2() << std::endl;
Result* result3 = new Result;
auto mg3 = [result3](){return result3->get("result3");};
std::cout << mg3() << std::endl;
delete result3;

Lambda demo

I highly recommend STL's CppCon 2015 talk about why bind() is all but deprecated in favor of lambdas.

Deduce member function return type using a class member function object

I have been troubled for hours or days around such problems. Typically gcc wants this-> but clang does not. In some cases Foo:: also helps but there have been cases where I have given up using the member names. The following is only using the type names and (though more verbose) I think will not have any problems with either:

template<typename Base, typename Acc>
struct Foo
{
Base base;
Acc acc;

template<typename S>
using result = typename std::result_of<S>::type;

auto operator()(unsigned i) const
-> result<const Acc(result<const Base(unsigned)>)>
{ return acc(base(i)); }
};

More generally, whenever decltype(member_name) is causing problems, you can safely use decltype(std::declval<member_type>()) where member_type is const-qualified if the member function using it is const.

Even more generally, if you have a member function that is &&, & or const& qualified, use member_type, member_type& or const member_type& respectively in such expressions.

I have never looked into what the standard says but in practice compilers treat expressions differently in trailing return types and inside function definitions when it comes to class members.

How do I know the actual type and size of the return type of a non-static method in C++?

The decltype specifier needs to be given a legal expression - something you could use in actual code. So you can create an instance and call the member on that instance like this:

decltype(std::vector<int>().size())

It is the same for the sizeof operator. It needs to receive a legal expression.



Related Topics



Leave a reply



Submit