【问题标题】:How to use boost::hana::unpack with the constructor, instead of function?如何将 boost::hana::unpack 与构造函数一起使用,而不是函数?
【发布时间】:2018-12-31 06:09:16
【问题描述】:

鉴于此示例代码,如何使用pars 调用构造函数来创建Foo2D 对象?

#include <boost/hana/tuple.hpp>
#include <boost/hana/unpack.hpp>

class Foo2D {
public:
    Foo2D(int x, int y):m_x(x), m_y(y) {}
private:
    int m_x;
    int m_y;
};

int main() {
    auto pars = boost::hana::make_tuple(10, 20);
    Foo2D foo1(10, 20); //my intention
    Foo2D foo2 = boost::hana::unpack(pars, Foo2D); //fails
}

【问题讨论】:

  • 您反对为此使用 lambda 吗?
  • 使用 lambda? boost::hana::unpack(pars, [](auto&amp;&amp;... args) {return Foo2D(args...);}).
  • @Jarod42, r3mus 是的,当然……显然,我对 c++ 元编程还是很陌生。谢谢你这么快的回复!

标签: c++ boost c++14 metaprogramming boost-hana


【解决方案1】:
template<class T>
constexpr auto ctor = [](auto&&...args)
  noexcept(noexcept(T{ decltype(args)(args)... }))
  -> decltype( T{ decltype(args)(args)... } )
  {
    return T{ decltype(args)(args)... };
  };

现在:

Foo2D foo2 = boost::hana::unpack(pars, ctor<Foo2D>);

应该可以。

或者:

// Object that represents constructing an object of type T:
template<class T>
struct ctor_t {
  template<class...Args>
  constexpr auto operator()(Args&&...args) const
  // propogate noexcept:
  noexcept(noexcept(T{ std::forward<Args>(args)... }))
  // SFINAE friendly:
  -> decltype( T{ std::forward<Args>(args)... } )
  {
    // notice this expression is repeated twice above:
    return T{ std::forward<Args>(args)... };
  }
  template<class A0, class...Args>
  constexpr auto operator()(std::initializer_list<A0> il, Args&&...args) const
  noexcept(noexcept( T{ il, std::forward<Args>(args)... } ))
  -> decltype(T{ il, std::forward<Args>(args)... })
  {
    return T{ il, std::forward<Args>(args)... };
  }
  constexpr ctor_t() {} // some compilers require this

  template<class...Args>
  constexpr (*operator T() const)(Args...) const {
    return +[](Args...args)->T {
      return ctor_t<T>{}(std::forward<Args>(args)...);
    };
  }
  explicit operator bool() const = delete;
};
template<class T>
constexpr ctor_t<T> ctor{};

如果您害怕 lambda 版本。这个版本还支持一个前导初始化列表和一个固定签名的隐式转换到工厂函数指针。

Live example。测试代码:

// construct an int 7:
auto x = ctor<int>( 7 );
std::cout << x << "\n";

// get a pointer to a constructor function
// that constructs an int from a short:
int(* pf)(short) = ctor<int>;
// run it:
std::cout << pf(0) << "\n";

【讨论】:

  • 并创建 2 个变体,一个带有 (),一个带有 {} :-)
  • @Jarod42 在工业强项中,我也会使用类而不是 lambda,并使用 operator()(initializer_list&lt;T&gt;, Ts&amp;&amp;...)Ts&amp;&amp;... 以获得更完美的完美转发。
  • 它的使用方式很酷,但ctor 的定义对于我组织中的普通(任何?)C++ 程序员来说肯定是无法理解的。我希望这个类是 C++ 标准库的一部分。
  • @AdamRyczkowski 好吧,如果它让您感觉更好,我添加了一个更详细的版本,其中包含更多功能。您现在可以使用返回 T 的函数指针,该指针接受任意参数并执行 T(*pfunc)(some_args) = ctor&lt;T&gt;;。 ;)
  • 正如我所说 - 你的 API 很棒。简单而优雅。现在更是如此:-)。但是,当我们所有人都是数据科学家,而不是专门的 C++ 程序员,并且需要大量的专门工作来真正遵循和理解这段代码时,我犹豫是否要在我们的项目中引入定义 ctor 的如此复杂的 C++ 代码。如果它在标准库中,我们可以简单地将其视为一个黑盒子,而无需费心去理解。
【解决方案2】:

构造函数不是函数或函子。您可以使用 lambda 或常规函数:

boost::hana::unpack(pars,
                    [](auto&&... args) {
                        return Foo2D(std::forward<decltype(args)>(args)...);
                    });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多