Inferring return type of templated member functions in CRTP

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

一个额外的间接是你的朋友:

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);
    }
};
链接地址: http://www.djcxy.com/p/82540.html

上一篇: 变量模板别名作为模板参数(第2部分)

下一篇: 推断CRTP中的模板成员函数的返回类型