C++高阶lambda无法推导出返回的lambda类型



我有一个任务要创建一个实际上通用的类,它可以获得某种整数输入源和某种消耗这些输入的消费者。我已经成功地实现了这一点,但它比我想要的更丑陋。所以这是我的解决方案的一部分。

这是我的输入源实现的接口:

class InputSource {
public:
virtual const InputSource& operator<<(int& num) const = 0;
virtual ~InputSource()=default;
};

这是一个从键盘获得输入的实现:

class KeyboardInput : public InputSource {
public:
KeyboardInput()=default;
virtual ~KeyboardInput()=default;
virtual const InputSource& operator<<(int& num) const override {
std::cin >> num;
return *this;
}
};

这是我对数字序列类的实现,它接收一些输入源,并执行一个操作,该操作是一个std::函数,对从输入源给出的数字进行操作

class NumberSequence {
const InputSource &input_source;
const std::function<void(int)> &action;
int next_num() {int num; input_source<<num; return (num<0 ? -1 : num);} // -1 if no morenumbers
public:
NumberSequence(const InputSource &input_source, const std::function<void(int)> &action) : input_source(input_source), action(action) {}
void start_action() {
int num;
do {
action(num = next_num());
if(num == -1) break;
std::this_thread::sleep_for(std::chrono::seconds(1));
} while(true);
}
};

这个类的肉是start_action成员函数,它从给定的输入源获取输入,然后用该数字调用action,等待1秒,直到输入源给出-1,就这么简单。

因此,现在我编写了一个操作的实现,它将这些数字输出到文件中,但不是作为一个类,而是作为一个lambda,如下所示:

static auto write_to_file_action = [](std::ofstream& output_file) {
return [&output_file](int num){
if(num == -1) return;
using namespace std::chrono;
time_point<system_clock> now = system_clock::now();
std::time_t time = system_clock::to_time_t(now);
output_file << num <<"t"<< std::ctime(&time) << std::endl;
};
};

这个lambda接收一个std::of流到我要输出数字的文件,加上它增加了时间,但它并不是真正相关的(部分是时间(。所以在我的主要功能中使用这个是这样的:

int main(void) {
KeyboardInput input_source;
std::ofstream output_file("output_file.txt");
NumberSequence num_seq(input_source, write_to_file_action(output_file));
num_seq.start_action();
return 0;
}

就像我说的这很有效,但我想有这样的东西:

int main(void) {
KeyboardInput input_source;
NumberSequence num_seq(input_source, write_to_file_action("output_file.txt"));
num_seq.start_action();
return 0;
}

这看起来很简单,但我很难实现它。我尝试过实现这样的write_to_file_action:

static auto write_to_file_action = [](const char* file_name) {
std::ofstream output_file(file_name);
return [output_file = std::move(output_file)](int num) mutable {
if(num == -1) return;
using namespace std::chrono;
time_point<system_clock> now = system_clock::now();
std::time_t time = system_clock::to_time_t(now);
output_file << num <<"t"<< std::ctime(&time) << std::endl;
};
};

但后来我得到了编译错误,基本上说这将不起作用,因为我的NumberSequence类想要一个std::函数,但std::功能必须是可复制的,而我的情况并非如此。在我的内部lambda的clojure中,我有一个std::ofstream,它是不可复制的。

所以我试着把NumberSequence类模板化如下:

template<typename Func>
class NumberSequence {
const InputSource &input_source;
const Func action;
int next_num() {int num; input_source<<num; return (num<0 ? -1 : num);} // -1 if no more numbers
public:
NumberSequence(const InputSource &input_source, Func &&action) 
: input_source(input_source), action(std::move(action)) {}
void start_action() {
int num;
do {
action(num = next_num());
if(num == -1) break;
std::this_thread::sleep_for(std::chrono::seconds(1));
} while(true);
}
};

这不会编译,但现在它没有编译,因为它说在main中num_seq变量之前缺少一个模板参数(它可以推断它(,所以我可以做这样的事情:

int main(void) {
KeyboardInput input_source;
auto lambda = write_to_file_action("output_file.txt");
NumberSequence<decltype(lambda)> num_seq(input_source, lambda);
num_seq.start_action();
return 0;
}

我还需要在NumberSequence中创建另一个构造函数,它接受对操作的普通引用,而不是右值引用。就像我很难过这工作,但我想删除这个明确的模板安装。我不知道这是否可能,但我看起来可能。如果有人能解释为什么它不能隐含地推导类型,因为我不明白。谢谢。

附言:很抱歉发了这么长的帖子,这是我第一次发帖子,我想了解我问题的全部背景。

C++14中lambda自动推导方法的示例。一个生成模板函数,该函数推导类型并返回适当创建的类模板。

#include <iostream>
#include <memory>
using namespace std;
template<typename PFunc>
class   CProcGuard
{
public:
CProcGuard(PFunc&& f):mFunc(std::move(f)){};
CProcGuard(CProcGuard&&) = default;
~CProcGuard()
{
mFunc();
}
private:
PFunc mFunc;
};
template<typename PFunc>
auto    ExecuteOnExit(PFunc&& f) -> CProcGuard<PFunc>
{
return CProcGuard<PFunc>(std::move(f)); // god bless RVO
}
int main()
{
std::unique_ptr<int> nonMovable =make_unique<int>(5);
auto exitGuard = ExecuteOnExit([nm = std::move(nonMovable)]()
{
cout<<"Hello World " << *nm;
});
return 0;
}

您的第二个选项是使lambda可通过std::shared_ptr移动。类似的东西:

static auto write_to_file_action = [](const char* file_name) {
auto ptr_output_file = std::make_shared<std::ofstream>(file_name);
return [ptr_output_file = std::move(ptr_output_file)](int num) mutable {
if(num == -1) return;
using namespace std::chrono;
time_point<system_clock> now = system_clock::now();
std::time_t time = system_clock::to_time_t(now);
*ptr_output_file  << num <<"t"<< std::ctime(&time) << std::endl;
};
};

有点笨,效率低,但它有效。

注意:做一个静态lambdawrite_to_file_action没有意义——只做一个正则函数——这可能会让一些人感到困惑。

最新更新