可变参数模板和std :: function

时间:2018-08-27 11:51:33

标签: c++ templates c++14 variadic-templates 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 个答案:

答案 0 :(得分:0)

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

没有特殊顺序...

(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()的{​​{1}}或更简单地制作publicd f的问题。

(2)struct不是初始化"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á!"); ,则必须将引用传递给对象,该对象的寿命应足以覆盖元组的寿命。

(3)std::string的{​​{1}}返回一个operator(),其中d的{​​{1}}接受三个参数:a std::tuple<int, float, std::string&&>,a operator()f

因此,就像在int中一样,您不能简单地将第一个返回的值传递给第二个,而不用解包float

std::string&&

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

a::operator()

所以您必须以某种方式进行仿真(bool operator()() { return m_f(m_d()); } // ........................^^^^^^^^^^ Wrong! std::apply()bool operator()() { return std::apply(m_f, m_d()); } // ........................^^^^^^^^^^^^^^^^^^^^^^ Starting from C++17 等)。

通过示例

std::make_index_sequence

其中std::index_sequence可以是std::get()