将铸造/结构转变为完美的可转发功能

时间:2014-06-24 15:41:14

标签: c++ rvalue-reference perfect-forwarding universal-reference

SSCCE:

#include <functional>

using std::function;
using std::forward;

template<typename ToType, typename... FromTypes>
ToType construct(FromTypes&&... fromTypes) {
  return ToType(forward<FromTypes>(fromTypes)...);
}

class Maybe {
public:
  Maybe() : m_value(42.0f) {}

  template<typename Function>
  auto apply(Function function) const -> decltype(function(std::declval<float>())) {
    return function(value());
  }

private:
  float const& value() const {
    return m_value;
  }

  float m_value;
};

int main() {
  Maybe a;

  a.apply(construct<int, float>);

  return 0;
}

给出错误:

test.cpp: In instantiation of ‘decltype (function(declval<float>())) Maybe::apply(Function) const [with Function = int (*)(float&&); decltype (function(declval<float>())) = int]’:
test.cpp:31:32:   required from here
test.cpp:17:28: error: invalid initialization of reference of type ‘float&&’ from expression of type ‘const float’
     return function(value());
                            ^

从错误消息中,value()返回const&这一事实显然是一个问题。

这里的关键点是,类型不是在第17行推断出来的,其中值正在传递给它。当construct函数在第31行传递给apply时,将分配该类型。

我为construct的模板指定了错误的类型。 construct<int, float>。如果我使用construct<int, float const&>,它的功能就可以了。

然而,这很麻烦,需要了解apply的实施情况。它也永远不会绑定左值,因为TT&&是不同的类型。 (因为缺少类型演绎。)

有没有办法让我可以传递给另一个函数的函数,并且在调用它的站点上进行类型推导,这样我可以或多或少透明地为调用者进行完美的转发?或者还有另一种方法可以实现这一目的,不会给调用者泄漏复杂性吗?

1 个答案:

答案 0 :(得分:2)

这个怎么样?

#include <functional>

using std::function;
using std::forward;

template<typename ToType>
class construct
{
public:
  template<typename... FromTypes>
  ToType operator()(FromTypes&&... fromTypes) {
    return ToType(forward<FromTypes>(fromTypes)...);
  }
};

class Maybe {
public:
  Maybe() : m_value(42.0f) {}

  template<typename Function>
  auto apply(Function function) const -> decltype(function(std::declval<float>())) {
    return function(value());
  }

private:
  float const& value() const {
    return m_value;
  }

  float m_value;
};

int main() {
  Maybe a;

  a.apply(construct<int>());

  return 0;
}

您只需指定要转换为的类型,这显然无法在您提供的上下文中推断出来。