使用函子的返回类型来声明模板方法的返回类型,不需要decltype

Using the return type of a functor to declare return type of a template method, without decltype

本文关键字:返回类型 模板方法 不需要 decltype 声明      更新时间:2023-10-16

我希望在调用模板成员函数时避免指定返回类型的需要。"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;
}
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_ofstd::tr1::result_of

据我所知,如果我们修改您的调用以包含&操作符,原始代码中唯一的错误是在谈论依赖类型时缺乏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所指出的,这只有在使用&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< Func_Type ( Args... ) >实际上是对返回 Func_Type并接受(Args...)的函数类型进行操作。然后它说"如果我们将Args...应用于Func_Type会怎么样?"当Func_Type是函数的实际类型时,这将不起作用,因为不允许返回函数的实际实例。

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