简体   繁体   English

可变参数模板和std :: function

[英]variadic template and std::function

In the following code: 在下面的代码中:

#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;
}

I get the compiler error: 我收到编译器错误:

../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> >&&>()>&&’

I do not understand why the compiler can not find a suitable conversion, as it is reported in the last line of the error. 我不明白为什么编译器找不到合适的转换,因为它在错误的最后一行中报告。

I am using g++ with flag '-std=c++14' on a Xubuntu box, and 'g++ --version' reports 'g++ (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609' 我正在Xubuntu框上使用带有标志'-std = c ++ 14'的g ++,并且'g ++ --version'报告'g ++(Ubuntu 5.4.0-6ubuntu1〜16.04.10)5.4.0 20160609'

Can anyone tell me what am I doing wrong? 谁能告诉我我在做什么错?

Thanks!! 谢谢!!

I see at least three errors in your code. 我在您的代码中看到至少三个错误。

In no particular order... 没有特别的顺序...

(1) if you want a functional, the operator() has to be public ; (1)如果您想要功能, operator()必须是public you make they both private 你让他们都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;
  }
};

You can solve this problem making operator() 's public or, maybe simpler, making d and f struct s. 您可以解决此问题,使operator() public ,或者使df struct更简单。

(2) "olá!" (2) "olá!" isn't a valid value to initialize a std::string && 不是初始化std::string &&的有效值

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

You can compile with 你可以用

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

but this is wrong idea because, this way, you initialize an object with a reference to an object that is destroyed immediately after and you obtain a dangling reference inside the tuple. 但这是一个错误的主意,因为用这种方式,您用一个对象的引用初始化了一个对象,该对象在此之后立即被销毁,并且在元组中获得了一个悬空的引用。

Isn't clear to me why you want to use a std::string && in the tuple but I suspect that you can use a std::string , not a reference to it. 我不清楚,为什么要在元组中使用std::string && ,但我怀疑您可以使用std::string ,而不是对其的引用。 In all your code, non only in this function. 在所有代码中,不仅限于此功能。

In this case, the following code 在这种情况下,以下代码

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

works. 作品。

If you really want a reference to a std::string in your tuple, you have to pass a reference to an object with a lifetime long enough to cover the lifetime of you tuple. 如果您确实要在元组中引用std::string ,则必须将引用传递给对象,该对象的生存期应足以覆盖元组的生存期。

(3) The operator() of d return a std::tuple<int, float, std::string&&> where the operator() of f accept three parameters: a int , a float and a std::string&& . (3) doperator()返回std::tuple<int, float, std::string&&> ,其中foperator()接受三个参数: intfloatstd::string&&

So you can't simply pass the value returned from the first to the second, without unpacking the std::tuple is some way, as you do in the a::operator() 因此,您不能简单地将第一个返回的值传递给第二个,而不用像打开a::operator()那样解压std::tuple

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

You're using C++14 so you can't use std::apply() (available starting from C++17) 您正在使用C ++ 14,因此无法使用std::apply() (可从C ++ 17开始使用)

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

so you have to emulate is in some way ( std::make_index_sequence , std::index_sequence , std::get() , etc.). 因此您必须以某种方式进行仿真( std::make_index_sequencestd::index_sequencestd::get()等)。

By example 举个例子

  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))...);
   }

where call() can be private 其中call()可以是private

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM