C++ 14引入了通用lambdas(在lambda签名中使用auto关键字时).
有没有办法将它们存储在带有C++ 17的向量中?
我知道这个现有的问题,但它不适合我的需要:我可以有一个模板函数指针的std :: vector吗?
这是一个示例代码,说明了我想要做的事情.(请在回答前查看底部的注释)
#include <functional>
#include <vector>
struct A {
void doSomething() {
printf("A::doSomething()\n");
}
void doSomethingElse() {
printf("A::doSomethingElse()\n");
}
};
struct B {
void doSomething() {
printf("B::doSomething()\n");
}
void doSomethingElse() {
printf("B::doSomethingElse()\n");
}
};
struct TestRunner {
static void run(auto &actions) {
A a;
for (auto &action : actions) action(a);
B b;
for (auto &action : actions) action(b); // I would like to do it
// C c; ...
}
};
void testCase1() {
std::vector<std::function<void(A&)>> actions; // Here should be something generic instead of A
actions.emplace_back([](auto &x) {
x.doSomething();
});
actions.emplace_back([](auto &x) {
x.doSomethingElse();
});
// actions.emplace_back(...) ...
TestRunner::run(actions);
}
void testCase2() {
std::vector<std::function<void(A&)>> actions; // Here should be something generic instead of A
actions.emplace_back([](auto &x) {
x.doSomething();
x.doSomethingElse();
});
actions.emplace_back([](auto &x) {
x.doSomethingElse();
x.doSomething();
});
// actions.emplace_back(...) ...
TestRunner::run(actions);
}
// ... more test cases : possibly thousands of them
// => we cannot ennumerate them all (in order to use a variant type for the actions signatures for example)
int main() {
testCase1();
testCase2();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
注意:
A,B并且TestRunner不能更改,只有测试用例的代码它遵循一个可能的解决方案(我不建议,但你明确表示你不想讨论它是好还是坏等等).
按照要求,A,B并TestRunner没有改变(抛开事实,auto不是一个有效的函数参数TestRunner,我把它相应的).
如果你可以略微改变TestRunner,整个事情都可以改进.
话虽这么说,这是代码:
#include <functional>
#include <vector>
#include <iostream>
#include <utility>
#include <memory>
#include <type_traits>
struct A {
void doSomething() {
std::cout << "A::doSomething()" << std::endl;
}
void doSomethingElse() {
std::cout << "A::doSomethingElse()" << std::endl;
}
};
struct B {
void doSomething() {
std::cout << "B::doSomething()" << std::endl;
}
void doSomethingElse() {
std::cout << "B::doSomethingElse()" << std::endl;
}
};
struct Base {
virtual void operator()(A &) = 0;
virtual void operator()(B &) = 0;
};
template<typename L>
struct Wrapper: Base, L {
Wrapper(L &&l): L{std::forward<L>(l)} {}
void operator()(A &a) { L::operator()(a); }
void operator()(B &b) { L::operator()(b); }
};
struct TestRunner {
static void run(std::vector<std::reference_wrapper<Base>> &actions) {
A a;
for (auto &action : actions) action(a);
B b;
for (auto &action : actions) action(b);
}
};
void testCase1() {
auto l1 = [](auto &x) { x.doSomething(); };
auto l2 = [](auto &x) { x.doSomethingElse(); };
auto w1 = Wrapper<decltype(l1)>{std::move(l1)};
auto w2 = Wrapper<decltype(l2)>{std::move(l2)};
std::vector<std::reference_wrapper<Base>> actions;
actions.push_back(std::ref(static_cast<Base &>(w1)));
actions.push_back(std::ref(static_cast<Base &>(w2)));
TestRunner::run(actions);
}
void testCase2() {
auto l1 = [](auto &x) {
x.doSomething();
x.doSomethingElse();
};
auto l2 = [](auto &x) {
x.doSomethingElse();
x.doSomething();
};
auto w1 = Wrapper<decltype(l1)>{std::move(l1)};
auto w2 = Wrapper<decltype(l2)>{std::move(l2)};
std::vector<std::reference_wrapper<Base>> actions;
actions.push_back(std::ref(static_cast<Base &>(w1)));
actions.push_back(std::ref(static_cast<Base &>(w2)));
TestRunner::run(actions);
}
int main() {
testCase1();
testCase2();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我无法看到在矢量中存储非齐次lambda的方法,因为它们只是非均匀类型.
无论如何,通过定义接口(请参阅参考资料Base)并使用Wrapper继承自给定接口和lambda 的模板类(请参阅参考资料),我们可以将请求转发给给定的通用lambda,并且仍然具有同构接口.
换句话说,解决方案的关键部分是以下类:
struct Base {
virtual void operator()(A &) = 0;
virtual void operator()(B &) = 0;
};
template<typename L>
struct Wrapper: Base, L {
Wrapper(L &&l): L{std::forward<L>(l)} {}
void operator()(A &a) { L::operator()(a); }
void operator()(B &b) { L::operator()(b); }
};
Run Code Online (Sandbox Code Playgroud)
可以从lambda创建包装器,如下所示:
auto l1 = [](auto &) { /* ... */ };
auto w1 = Wrapper<decltype(l1)>{std::move(l1)};
Run Code Online (Sandbox Code Playgroud)
不幸的是,由于要求是不修改TestRunner,我必须使用std::ref并std::reference_wrapper能够在向量中放置引用.
在wandbox上看到它.
| 归档时间: |
|
| 查看次数: |
992 次 |
| 最近记录: |