可变模板和 std::function

variadic template and std::function

在下面的代码中:

#include <functional>
#include <iostream>
#include <tuple>

template <typename... t>
class a {
 public:
  explicit a(std::function<std::tuple<t...>()>&& p_d,
             std::function<bool(t...)>&& p_f)
      : m_d(std::move(p_d)), m_f(std::move(p_f)) {}

  bool operator()() { return m_f(m_d()); }

 private:
  std::function<std::tuple<t...>()> m_d;
  std::function<bool(t...)> m_f;
};

class d {
  std::tuple<int, float, std::string&&> operator()() {
    return std::tuple<int, float, std::string&&>(-9, 3.14, "olá!");
  }
};

class f {
  bool operator()(int p_i, float p_f, std::string&& p_s) {
    std::cout << "i = " << p_i << ", f = " << p_f << ", s = " << p_s
              << std::endl;
    return true;
  }
};

int main() {
  d _d;
  f _f;
  typedef a<int, float, std::string&&> a_t;

  a_t _a(std::move(_d), std::move(_f));

  _a();

  return 0;
}

我收到编译器错误:

../untitled014/main.cpp: In function ‘int main()’:
../untitled014/main.cpp:38:38: error: no matching function for call to ‘a<int, float, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&>::a(std::remove_reference<d&>::type, std::remove_reference<f&>::type)’
   a_t _a(std::move(_d), std::move(_f));
                                      ^
../untitled014/main.cpp:8:12: note: candidate: a<t>::a(std::function<std::tuple<_Elements ...>()>&&, std::function<bool(t ...)>&&) [with t = {int, float, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&}]
   explicit a(std::function<std::tuple<t...>()>&& p_d,
            ^
../untitled014/main.cpp:8:12: note:   no known conversion for argument 1 from ‘std::remove_reference<d&>::type {aka d}’ to ‘std::function<std::tuple<int, float, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&>()>&&’

我不明白为什么编译器找不到合适的转换,因为它在错误的最后一行中报告。

我在 Xubuntu 盒子上使用带有标志“-std=c++14”的 g++,'g++ --version' 报告 'g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609'

谁能告诉我我做错了什么?

谢谢!!

我在您的代码中看到至少三个错误。

排名不分先后...

(1) 如果你想要函数式,operator() 必须是 public;你让他们都 private

class d { // default for a class is private, so operator() is private
  std::tuple<int, float, std::string&&> operator()() {
    return std::tuple<int, float, std::string&&>(-9, 3.14, "olá!");
  }
};

class f { // default per a class is private, so operator() is private
  bool operator()(int p_i, float p_f, std::string&& p_s) {
    std::cout << "i = " << p_i << ", f = " << p_f << ", s = " << p_s
              << std::endl;
    return true;
  }
};

你可以解决这个问题制作 operator()public 或者,也许更简单,制作 df structs.

(2) "olá!" 不是初始化 std::string &&

的有效值
 std::tuple<int, float, std::string&&>(-9, 3.14, "olá!");

你可以用

编译
 std::tuple<int, float, std::string&&>(-9, 3.14, std::string{"olá!"});

但这是错误的想法,因为通过这种方式,您可以使用对随后立即销毁的对象的引用来初始化对象,并在元组中获得悬空引用。

我不清楚为什么要在元组中使用 std::string &&,但我怀疑您可以使用 std::string,而不是对它的引用。在你所有的代码中,不仅在这个函数中。

在这种情况下,下面的代码

std::tuple<int, float, std::string>(-9, 3.14, "olá!");

有效。

如果你真的想在你的元组中引用一个 std::string,你必须传递一个对生命周期足够长的对象的引用来覆盖你的元组的生命周期。

(3) The operator() of d return a std::tuple<int, float, std::string&&> where the operator() of f 接受三个参数:a int、一个 float 和一个 std::string&&.

所以你不能像在 a::operator()

bool operator()() { return m_f(m_d()); }
// ........................^^^^^^^^^^  Wrong!

你正在使用 C++14,所以你不能使用 std::apply()(从 C++17 开始可用)

bool operator()() { return std::apply(m_f, m_d()); }
// ........................^^^^^^^^^^^^^^^^^^^^^^  Starting from C++17

所以你必须以某种方式模仿(std::make_index_sequencestd::index_sequencestd::get() 等)。

举例

  bool operator() ()
   { return call(std::make_index_sequence<sizeof...(t)>{}); }

  template <std::size_t ... Is>
  auto call (std::index_sequence<Is...> const &)
   {
     auto tmp { m_d() }; // so m_d() is called only one time

     return m_f(static_cast<t>(std::get<Is>(tmp))...);
   }

其中 call() 可以是 private