我正在编写一个程序,它将充当类之间的控制器。本质上,类都有getter和setter,但是getter和setter有不同的名称,有些执行不同的操作。例如,ClassA
有一个二传手setValue
,但ClassB
有一个名为updateValue
的二传手。这些类已经编写好了,我不想重写每个类都有相同的名称,因为它们已经嵌入代码库中。相反,我已经在每个类中编写了一个updateVariable
函数,它将调用它的各自的setter。
现在我已经解释了,我将展示控制器类:
#ifndef CONTROLLER_HPP
#define CONTROLLER_HPP
#include <functional>
#include <vector>
#include <iostream>
class Controller
{
public:
template <class...Classes>
Controller(Classes & ...classes)
{
toSet = [&](int val){(classes.updateValue(val), ...); };
toGet = [&](){ return (classes.get(), ...); };
}
void setValues(int val)
{
toSet(val);
}
std::vector<int> getValues()
{
std::vector<int> values;
values.emplace_back(toGet());
return values;
}
private:
std::function<void(int)> toSet;
std::function<int()> toGet;
};
#endif
我仍然不确定toSet
是如何工作的,例如,如果我在main中声明:
int main()
{
ClassA a;
ClassB b;
ClassC c;
Controller control(A,B,C);
control.setValues(20);
}
这会将所有类的值设置为20.但我不知道魔法是如何工作的,因为它似乎只被调用一次。然而,当我用toGet
尝试同样的事情时,我只得到一个值。所以我很困惑为什么这不起作用。
让我们从你的问题“toSet
如何运作”的这一部分开始。让我们摆脱variadic
模板,让事情更清洁:
Controller(ClassA& classA, ClassB& classB, Class C& classC)
{
toSet = [&](int val){
classA.updateValue(val);
classB.updateValue(val);
classC.updateValue(val);
};
}
(从技术上讲,我认为它使用逗号运算符,但足够接近。)
本质上,这是创建一个lambda
,为传入的三个实例中的每一个调用updateValue
。它通过lambda捕获保存对这些实例的引用。
如果你同样扩展你的toGet
代码,你会得到一些毫无意义的东西:
toGet = [&](){
return classA.get(), classB.get(), classC.get();
};
换句话说,toGet
只能返回一个值,尽管它会调用所有三个getter。讨厌的逗号操作员!
相反,您可以更改toGet
以便它返回一个向量。基本上,你想要它做:
toGet = [&](){
std::vector<int> values;
values.emplace_back(classA.get());
values.emplace_back(classA.get());
values.emplace_back(classA.get());
return values;
};
C ++ 17方法:如果您正在使用c ++ 17,并且如果您可以使用模板类而不是仅使用set和get函数模板:
#include <functional>
#include <vector>
#include <iostream>
#include <utility>
template <typename... Class>
class Controller
{
public:
Controller(Class& ...objects)
: objects(objects...)
{
}
void getValuesInTo(std::vector<int> &values)
{
std::apply([&](auto... x){ (values.push_back(x.get()), ...);}, objects);
}
private:
std::tuple<Class&...> objects;
};
struct ClassA
{
int get() { return 1;};
};
struct ClassB
{
int get() { return 2;};
};
struct ClassC
{
int get() { return 3;};
};
int main()
{
ClassA a;
ClassB b;
ClassC c;
auto control = Controller(a,b,c);
std::vector<int> res;
control.getValuesInTo(res);
for(auto a : res) std::cout << a;
}
在C ++中,在语句之间放置逗号会丢弃除最后一个语句之外的所有内容的返回值:
int x = (10, 20, "Hello", 30);
// x is 30
逗号运算符用于两个地方。在这里,与toSet
:
toSet = [&](int val){(classes.updateValue(val), ...); };
在这里,与toGet
:
toGet = [&](){ return (classes.get(), ...); };
toSet
工作正常,因为你不关心updateValue
的回报价值。您所做的只是更新值。但是,toGet
仅返回传入的最后一个值。
如果get()
总是为所有类返回相同的类型(例如,int),我们可以修改toGet
以返回向量:
// Declaration:
// std::function<std::vector<int>()> toGet;
toGet = [&]() { return std::vector<int>{classes.get()...}; };