可变参数和函数指针向量
Variadic arguments and function pointers vector
我在使用 C++11 时遇到了一个几乎合乎逻辑的问题。
我有一个 class 我必须绘制(又名绘制趋势)并且我想排除所有不满足给定条件的点。
这些点属于 class Foo
并且所有条件函数都使用签名 bool Foo::Bar(Args...) const
定义,其中 Args...
表示许多参数(例如,返回值的上限和下限值)。
一切顺利,直到我希望对要绘制的值应用单一条件。假设我有一个 FooPlotter
class,它有类似的东西:
template<class ...Args> GraphClass FooPlotter::Plot([...],bool (Foo::*Bar)(Args...), Args... args)
这将遍历我的数据容器并将条件 Foo::*Bar
应用于所有元素,绘制满足给定条件的值。
到目前为止一切顺利。
在给定的时间点,我想将一个条件向量传递给相同的方法,以便使用多个条件来过滤数据。
我首先创建了一个 class 来包含我以后需要的所有东西:
template<class ...Args> class FooCondition{
public:
FooCondition(bool (Foo::*Bar)(Args...) const, Args... args)
{
fCondition = Bar;
fArgs = std::make_tuple(args);
}
bool operator()(Foo data){ return (data.*fCondition)(args); }
private:
bool (Foo::*fCondition)(Args...) const;
std::tuple<Args...> fArgs;
};
然后我陷入了如何定义一个(可迭代的)容器的问题,它可以包含 FooCondition
对象,尽管它们有多种类型用于 Args...
参数包。
问题是有些方法有 Args... = uint64_t,uint_64_t
而其他方法不需要调用参数。
我深入了解了如何处理这种情况。我尝试了几种方法,但其中 none 效果很好。
目前我向所有 Bar
方法添加了忽略的参数,将它们统一化并解决了这个问题,但我不是很满意!
你们中有人知道如何以优雅的方式存储不同类型的 FooCondition
对象吗?
编辑:关于我想要获得的结果的附加信息。
首先,我希望能够创建 std::vector
个 FooCondition
项:
std::vector<FooCondition> conditions;
conditions.emplace_back(FooCondition(&Foo::IsBefore, uint64_t timestamp1));
conditions.emplace_back(FooCondition(&Foo::IsAttributeBetween, double a, double b));
conditions.emplace_back(FooCondition(&Foo::IsOk));
在这一点上,我希望我可以在我的 FooPlotter::Plot
方法中执行如下操作:
GraphClass FooPlotter::Plot(vector<Foo> data, vector<FooCondition> conditions){
GraphClass graph;
for(const auto &itData : data){
bool shouldPlot = true;
for(const auto &itCondition : conditions){
shouldPlot &= itCondition(itData);
}
if(shouldPlot) graph.AddPoint(itData);
}
return graph;
}
正如您所说,FooCondition struct
应该使用重载运算符自动将正确的参数传递给方法。
这里的问题是找到正确的容器来创建 FooCondition
模板的集合,尽管它们的参数包很大。
除了所有的 foo 栏,你只需要一个 class 和一个可以实现的方法来满足情节。
只需在接受节点的 class 上添加一个 Plot 方法,并在同一步骤中执行转换和绘图。
绘图时无需担心参数,因为每个函数都知道它需要什么参数。
因此一个简单的 args* 就足够了,当 null 没有参数时,其中每个 arg 显示它的类型和值,或者可以从函数调用中假定。
在我看来,对于 FooCondition
,您正在尝试创建 std::function<bool(Foo *)>
(或者 std::function<bool(Foo const *)>
)的替代品,并使用 std::bind
进行初始化修复 Foo
方法的一些参数。
我的意思是...我认为
std::vector<FooCondition> conditions;
conditions.emplace_back(FooCondition(&Foo::IsBefore, uint64_t timestamp1));
conditions.emplace_back(FooCondition(&Foo::IsAttributeBetween, double a, double b));
conditions.emplace_back(FooCondition(&Foo::IsOk));
你应该这样写
std::vector<std::function<bool(Foo const *)>> vfc;
using namespace std::placeholders;
vfc.emplace_back(std::bind(&Foo::IsBefore, _1, 64U));
vfc.emplace_back(std::bind(&Foo::IsAttributeBetween, _1, 10.0, 100.0));
vfc.emplace_back(std::bind(&Foo::IsOk, _1));
以下是一个简化的完整工作 C++11 示例,其中包含一个模拟 Plot()
的 main()
#include <vector>
#include <iostream>
#include <functional>
struct Foo
{
double value;
bool IsBefore (std::uint64_t ts) const
{ std::cout << "- IsBefore(" << ts << ')' << std::endl;
return value < ts; }
bool IsAttributeBetween (double a, double b) const
{ std::cout << "- IsAttrributeBetwen(" << a << ", " << b << ')'
<< std::endl; return (a < value) && (value < b); }
bool IsOk () const
{ std::cout << "- IsOk" << std::endl; return value != 0.0; }
};
int main ()
{
std::vector<std::function<bool(Foo const *)>> vfc;
using namespace std::placeholders;
vfc.emplace_back(std::bind(&Foo::IsBefore, _1, 64U));
vfc.emplace_back(std::bind(&Foo::IsAttributeBetween, _1, 10.0, 100.0));
vfc.emplace_back(std::bind(&Foo::IsOk, _1));
std::vector<Foo> vf { Foo{0.0}, Foo{10.0}, Foo{20.0}, Foo{80.0} };
for ( auto const & f : vf )
{
bool bval { true };
for ( auto const & c : vfc )
bval &= c(&f);
std::cout << "---- for " << f.value << ": " << bval << std::endl;
}
}
另一种方法是避免使用 std::bind
并改用 lambda 函数。
举例
std::vector<std::function<bool(Foo const *)>> vfc;
vfc.emplace_back([](Foo const * fp)
{ return fp->IsBefore(64U); });
vfc.emplace_back([](Foo const * fp)
{ return fp->IsAttributeBetween(10.0, 100.0); });
vfc.emplace_back([](Foo const * fp)
{ return fp->IsOk(); });
我在使用 C++11 时遇到了一个几乎合乎逻辑的问题。
我有一个 class 我必须绘制(又名绘制趋势)并且我想排除所有不满足给定条件的点。
这些点属于 class Foo
并且所有条件函数都使用签名 bool Foo::Bar(Args...) const
定义,其中 Args...
表示许多参数(例如,返回值的上限和下限值)。
一切顺利,直到我希望对要绘制的值应用单一条件。假设我有一个 FooPlotter
class,它有类似的东西:
template<class ...Args> GraphClass FooPlotter::Plot([...],bool (Foo::*Bar)(Args...), Args... args)
这将遍历我的数据容器并将条件 Foo::*Bar
应用于所有元素,绘制满足给定条件的值。
到目前为止一切顺利。
在给定的时间点,我想将一个条件向量传递给相同的方法,以便使用多个条件来过滤数据。
我首先创建了一个 class 来包含我以后需要的所有东西:
template<class ...Args> class FooCondition{
public:
FooCondition(bool (Foo::*Bar)(Args...) const, Args... args)
{
fCondition = Bar;
fArgs = std::make_tuple(args);
}
bool operator()(Foo data){ return (data.*fCondition)(args); }
private:
bool (Foo::*fCondition)(Args...) const;
std::tuple<Args...> fArgs;
};
然后我陷入了如何定义一个(可迭代的)容器的问题,它可以包含 FooCondition
对象,尽管它们有多种类型用于 Args...
参数包。
问题是有些方法有 Args... = uint64_t,uint_64_t
而其他方法不需要调用参数。
我深入了解了如何处理这种情况。我尝试了几种方法,但其中 none 效果很好。
目前我向所有 Bar
方法添加了忽略的参数,将它们统一化并解决了这个问题,但我不是很满意!
你们中有人知道如何以优雅的方式存储不同类型的 FooCondition
对象吗?
编辑:关于我想要获得的结果的附加信息。
首先,我希望能够创建 std::vector
个 FooCondition
项:
std::vector<FooCondition> conditions;
conditions.emplace_back(FooCondition(&Foo::IsBefore, uint64_t timestamp1));
conditions.emplace_back(FooCondition(&Foo::IsAttributeBetween, double a, double b));
conditions.emplace_back(FooCondition(&Foo::IsOk));
在这一点上,我希望我可以在我的 FooPlotter::Plot
方法中执行如下操作:
GraphClass FooPlotter::Plot(vector<Foo> data, vector<FooCondition> conditions){
GraphClass graph;
for(const auto &itData : data){
bool shouldPlot = true;
for(const auto &itCondition : conditions){
shouldPlot &= itCondition(itData);
}
if(shouldPlot) graph.AddPoint(itData);
}
return graph;
}
正如您所说,FooCondition struct
应该使用重载运算符自动将正确的参数传递给方法。
这里的问题是找到正确的容器来创建 FooCondition
模板的集合,尽管它们的参数包很大。
除了所有的 foo 栏,你只需要一个 class 和一个可以实现的方法来满足情节。
只需在接受节点的 class 上添加一个 Plot 方法,并在同一步骤中执行转换和绘图。
绘图时无需担心参数,因为每个函数都知道它需要什么参数。
因此一个简单的 args* 就足够了,当 null 没有参数时,其中每个 arg 显示它的类型和值,或者可以从函数调用中假定。
在我看来,对于 FooCondition
,您正在尝试创建 std::function<bool(Foo *)>
(或者 std::function<bool(Foo const *)>
)的替代品,并使用 std::bind
进行初始化修复 Foo
方法的一些参数。
我的意思是...我认为
std::vector<FooCondition> conditions;
conditions.emplace_back(FooCondition(&Foo::IsBefore, uint64_t timestamp1));
conditions.emplace_back(FooCondition(&Foo::IsAttributeBetween, double a, double b));
conditions.emplace_back(FooCondition(&Foo::IsOk));
你应该这样写
std::vector<std::function<bool(Foo const *)>> vfc;
using namespace std::placeholders;
vfc.emplace_back(std::bind(&Foo::IsBefore, _1, 64U));
vfc.emplace_back(std::bind(&Foo::IsAttributeBetween, _1, 10.0, 100.0));
vfc.emplace_back(std::bind(&Foo::IsOk, _1));
以下是一个简化的完整工作 C++11 示例,其中包含一个模拟 Plot()
main()
#include <vector>
#include <iostream>
#include <functional>
struct Foo
{
double value;
bool IsBefore (std::uint64_t ts) const
{ std::cout << "- IsBefore(" << ts << ')' << std::endl;
return value < ts; }
bool IsAttributeBetween (double a, double b) const
{ std::cout << "- IsAttrributeBetwen(" << a << ", " << b << ')'
<< std::endl; return (a < value) && (value < b); }
bool IsOk () const
{ std::cout << "- IsOk" << std::endl; return value != 0.0; }
};
int main ()
{
std::vector<std::function<bool(Foo const *)>> vfc;
using namespace std::placeholders;
vfc.emplace_back(std::bind(&Foo::IsBefore, _1, 64U));
vfc.emplace_back(std::bind(&Foo::IsAttributeBetween, _1, 10.0, 100.0));
vfc.emplace_back(std::bind(&Foo::IsOk, _1));
std::vector<Foo> vf { Foo{0.0}, Foo{10.0}, Foo{20.0}, Foo{80.0} };
for ( auto const & f : vf )
{
bool bval { true };
for ( auto const & c : vfc )
bval &= c(&f);
std::cout << "---- for " << f.value << ": " << bval << std::endl;
}
}
另一种方法是避免使用 std::bind
并改用 lambda 函数。
举例
std::vector<std::function<bool(Foo const *)>> vfc;
vfc.emplace_back([](Foo const * fp)
{ return fp->IsBefore(64U); });
vfc.emplace_back([](Foo const * fp)
{ return fp->IsAttributeBetween(10.0, 100.0); });
vfc.emplace_back([](Foo const * fp)
{ return fp->IsOk(); });