使用仿函数的返回类型来声明模板方法的返回类型,而不使用decltype

时间:2013-04-24 15:58:32

标签: c++ templates generics functor

我想避免在调用模板成员函数时指定返回类型。 '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;
}

2 个答案:

答案 0 :(得分: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_ofstd::tr1::result_of

答案 1 :(得分:1)

据我所知,如果我们修改您的调用以包含&运算符,原始代码中的唯一错误是在讨论依赖类型时缺少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_ofhttp://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::decayFunc_Type作为函数的类型转换为指向同一类型函数的指针,这是函数可以返回的函数。并且你可以像调用实际函数一样调用指向函数的指针,所以也没有任何伤害。