Inferring return type of templated member functions in CRTP

断了今生、忘了曾经 提交于 2019-11-29 18:21:33

问题


Is it possible to infer the return type of a templated member function in a CRTP base class?

While inferring argument types works well, it fails with the return type. Consider the example below.

#include <iostream>

template <typename Derived>
struct base
{
  template <typename R, typename T>
  R f(T x)
  {
    return static_cast<Derived&>(*this).f_impl(x);
  }
};

struct derived : base<derived>
{
  bool f_impl(int x)
  {
    std::cout << "f(" << x << ")" << std::endl;
    return true;
  }
};

int main()
{
  bool b = derived{}.f(42);
  return b ? 0 : 1;
}

This produces the following error:

  bool b = derived{}.f(42);
           ~~~~~~~~~~^
crtp.cc:7:5: note: candidate template ignored: couldn't infer template argument 'R'
  R f(T x)
    ^
1 error generated.

My intuitive assumption is that if the compiler is capable of inferring type int for the argument to f, it should also work for the return bool, because both types are known at template instantiation time.

I tried using the trailing return type function syntax, but then failed to find a working expression to put in decltype.

EDIT 1

For the case where the function has one or more templated arguments, Dietmar Kühl provided a solution based on delaying template instantiation using on layer of indirection. Unfotunately, this does not work when a base class function does not have any argument, like this:

template <typename R>
R g()
{
  return static_cast<Derived&>(*this).g_impl();
}

Attempts to use the same technique fail because there exist no dependent types. How does one handle this case?

EDIT 2

As pointed out by Johannes Schaub, C++11 features default template arguments, so it is always possible to make g dependent on an arbitrary type and then apply Dietmar's solution:

template <typename T = void>
auto g() -> typename g_impl_result<Derived, T>::type
{
  return static_cast<Derived&>(*this).g_impl();
}

EDIT 3

This problem does not exist in C++14 anymore, since we have return type deduction for normal functions, allowing us to write simply:

template <typename Derived>
struct base
{
  template <typename T>
  auto f(T x)
  {
    return static_cast<Derived&>(*this).f_impl(x);
  }

  auto g()
  {
    return static_cast<Derived&>(*this).g_impl();
  }
};

struct derived : base<derived>
{
  bool f_impl(int x)
  {
    return true;
  }

  double g_impl()
  {
    return 4.2;
  }
};

回答1:


An extra indirection is your friend:

template <typename D, typename T>
struct f_impl_result
{
    typedef decltype(static_cast<D*>(0)->f_impl(std::declval<T>())) type;
};

template <typename Derived>
struct base
{
    template <typename T>
    auto f(T x) -> typename f_impl_result<Derived, T>::type
    {
        return static_cast<Derived&>(*this).f_impl(x);
    }
};


来源:https://stackoverflow.com/questions/18392225/inferring-return-type-of-templated-member-functions-in-crtp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!