【问题标题】:Using the return type of a functor to declare return type of a template method, without decltype使用函子的返回类型来声明模板方法的返回类型,无需 decltype
【发布时间】:2013-04-18 06:51:03
【问题描述】:

我想避免在调用模板成员函数时指定返回类型。 'decltype' 关键字与 'auto' 结合可以实现这一点,但不幸的是,我们没有适用于我们需要支持的所有平台的 C++11 编译器。使用类型限定模板方法应用程序也可以,但需要调用者...使用类型限定模板方法。

以下是否可能,有一些模板魔法? boost 1.48 在这里提供任何帮助吗?

我们的实际代码是利用 boost::thread、boost::packaged_task 和 boost::unique_future,但这里是一个人为的例子:

#include <functional>

#ifdef WONT_COMPILE
struct WrapNoDecltype
{
    WrapNoDecltype() {}

    template<typename F>
    std::result_of<F>::type // warning: 'std::result_of<_Fty>::type' : dependent name is not a type
    operator()(const F& f)
    {
        setup();
        std::result_of<F>::type result = f();
        teardown();

        return result;
    }

    void setup() { }
    void teardown() { }
};
#endif

struct Wrap
{
    Wrap() {}

    template<typename F>
    auto operator()(const F& f) -> decltype(f())
    {
        setup();
        typename std::result_of<F()>::type result = f();
        teardown();

        return result;
    }

    void setup() { }
    void teardown() { }
};

struct WrapWithReturnType
{
    WrapWithReturnType() {}

    template<typename RetType>
    RetType
    apply(const std::function<RetType(void)>& f)
    {
        setup();
        RetType result = f();
        teardown();

        return result;
    }

    void setup() { }
    void teardown() { }
};

int answer()
{
    return 42;
}

int main()
{
    Wrap w;
    WrapWithReturnType wwr;
#ifdef WONT_COMPILE
    WrapNoDecltype wna;
#endif

    int i = w(answer);
    int j = wwr.apply<int>(answer);
#ifdef WONT_COMPILE
    int k = wna(answer);
#endif
    return 0;
}

【问题讨论】:

  • 您需要typename 来避免警告(甚至应该是错误),例如typename std::result_of&lt;F&gt;::type。
  • @DyP 错误的问题?据我所知,这个问题并没有这么说。它说std::result_of 适用于类型,而不是函数实例,这与您所说的不同......
  • @Yakk ?? OP 的代码中有一条注释说明存在警告,并且在 main 函数中将非成员函数传递给 operator (),因此 std::result_of 使用非成员函数的类型进行实例化
  • @Yakk 还是我的参考? answer 声明 std::result_of 不适用于非成员函数(函数类型);该问题的OP也有类似的问题。
  • @DyP 您似乎误读了答案。它声明它不适用于 instances 函数。它声明它适用于类型的函数。

标签: c++ templates generics functor


【解决方案1】:
struct WrapNoDecltype
{
    WrapNoDecltype() {}

    // version for function references
    template < typename Res >
    Res operator()( Res(&f)() )
    {
        setup();
        Res result = f();
        teardown();

        return result;
    }

    // version for everything
    template < typename T >
    typename std::result_of<typename std::decay<T>::type ()>::type
    operator()( T const& f )
    {
        setup();
        typename std::result_of<typename std::decay<T>::type ()>::type result = f();
        teardown();

        return result;
    }

    void setup() { }
    void teardown() { }
};

正如Yakk 指出的那样,通过合并decay,第二个版本始终有效。第一个版本要简单得多,但仅在传递函数引用时才有效。

当然,你也可以使用boost::result_of或std::tr1::result_of。

【讨论】:

  • std::result_of&lt;T()&gt; 不使用默认构造函数。 T() 不是一个值,而是一个函数类型。 result_of使用declval获取值,所以不会出现默认构造函数问题。
  • 如果f是一个函数,那么typename std::result_of&lt;T()&gt;::type operator()( T const&amp; f )返回返回f的函数类型,而不是返回f()的函数类型...
  • @Yakk 如果f 是一个函数,应该调用第一个版本,因为它更专业——还是我错了? result_of&lt;int()&gt; 格式不正确
  • @DyP 抱歉,误解了如何在空函数类型上使用 std::result_of!
【解决方案2】:

据我所知,如果我们修改您的调用以包含 &amp; 运算符,则原始代码中唯一的错误是在谈论依赖类型时缺少 typename,并且缺少参数列表拨打std::result_of时:

struct WrapNoDecltype
{
  WrapNoDecltype() {}

  template < typename T >
  typename std::result_of<T()>::type operator()( T const &f )
  {
    setup();
    typename std::result_of<T()>::type result = f();
    teardown();

    return result;
  }
};

但是,std::result_of 是 C++11 特征类,因此如果您的编译器不支持 decltype,它可能无法正确支持 std::result_of。

std::tr1::result_of 可能有妨碍上述工作的怪癖。

在野外,在函数指针类型上使用std::result_of:http://ideone.com/dkGid8

正如@DyP 所指出的,这仅在您使用&amp;f 而不是f 调用它时才有效。要解决此问题,请像这样使用std::decay:

struct WrapNoDecltype
{
  WrapNoDecltype() {}

  template < typename T >
  typename std::result_of<typename std::decay<T>::type()>::type
    operator()( T const &f )
  {
    // setup()
    typename std::result_of<typename std::decay<T>::type()>::type
      result = f();
    // teardown()

    return result;
  }
};

int foo() { return 7; }
int main()
{
  WrapNoDecltype test;
  int x = test(foo);
}

将函数类型转换为函数指针类型。

这是必需的,因为 std::result_of 滥用 C++ 语法。 std::result_of&lt; Func_Type ( Args... ) &gt; 实际上是对 返回 Func_Type 并采用 (Args...) 的函数类型进行操作。然后它说“如果我们将Args... 应用于Func_Type 会怎样。当Func_Type 是函数的实际类型时,这将无法工作,因为不允许您返回函数的实际实例。

std::decay 将 Func_Type 作为函数的类型转换为指向相同类型函数的指针,这是函数可以返回的东西。你可以像调用一个实际函数一样调用一个指向函数的指针,所以也没有什么坏处。

【讨论】:

  • std::result_of&lt;int()&gt;::type i; 格式不正确,这就是它无法在 AFAIK 中工作的原因。
  • @DyP Fixed -- typedef int(*func)(); std::result_of&lt; func() &gt;::type i; 格式正确。我误解了 result_of 文档中的无效函数。固定!
  • :) 一个棘手的问题......一个返回函数指针的函数.. 虽然,正如你所说,它只在通过 wna( &amp;answer ); 而不是 wna(answer); 调用时才有效
  • @DyP decay 但是,解决了这个问题。
  • 很好,+1。我现在也可以删除我的答案:(
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-21
  • 1970-01-01
  • 2016-05-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多