Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function with return type based on a protected base class method

I'm trying to let the return type of doSomeMethod() be the same as the operator() in the base class but if it's declared as protected the compiler rejects the code with error: no type named 'type' in 'std::result_of'. It works if it's public but i wonder if I could get it working for the protected case too since.

Here is simple code reproducing the error.

#include <type_traits>

class base
{
protected:
    int operator()(){return 1;};
};

class child : private base
{
    auto static doSomeMethod()
            -> typename std::result_of<base()>::type
    {
        return 1;
    }
};

EDIT:

Ok thanks Kerrek SB and Dietmar Kühlr for your solutions and explanations. After playing around with it I found this solution that is more readable and works (at least in my real case where child is template class and base one of its template parameters) more reliable. But it seems that it goes a bit against your explanations. Or is it just the way std::result_of<> is broken in this case?

#include <type_traits>

class base
{
protected:
    double operator()(){ return 1; };
    int operator()(int i){ return i; };
};

class child : private base 
{
  public:
    auto operator()()
      -> decltype(base::operator()()) 
    {
        return base::operator()();
    }

  auto operator()(int i)
      -> decltype(base::operator()(std::declval<int>())) 
    {
         return base::operator()(i);
    }
};

Thanks for your time.

like image 587
Drek Avatar asked Mar 22 '23 03:03

Drek


2 Answers

If your code is literally this, then you can exploit the fact that the protected operator() from base is also available in child, and use a simple trait:

template <typename> struct memfn_result;

template <typename C, typename R, typename ...Args>
struct memfn_result<R (C::*)(Args...)>
{
    using type = R;
};

class base
{
protected:
    int operator()(){ return 1; };
};

class child : private base
{
    memfn_result<decltype(&child::operator())>::type a;    // "a" is an "int"
};
like image 157
Kerrek SB Avatar answered Mar 23 '23 15:03

Kerrek SB


Since base::operator()() is protected and you are using it on an object of type base rather than an object of type child you clearly can't access the member! You need to access the function call operator using an object of type child. Sadly, child is incomplete in the context where you are trying to access it, i.e., you need to an indirection:

class child
    : private base {
    auto static doSomeMethod()
        -> decltype((std::declval<base>().*(&child::operator()))()) {
        return 1;
    }
};
like image 35
Dietmar Kühl Avatar answered Mar 23 '23 17:03

Dietmar Kühl