将动态仿函数传递给 stl
Passing dynamic functor to stl
我对 C++ 比较陌生,这是我第一次接触 post,所以请保持温和 ;-)
我了解如何传递函数指针或函数对象,就像许多 stl 函数所要求的那样。我不清楚如何将它与继承结合使用。
具体来说,我想用几个从基本仿函数继承的仿函数来调用一个 stl 函数。我没有找到关于这个主题的任何相关评论或最佳实践。这里有一个简化的代码片段:
struct generator{
virtual int operator()() = 0;
virtual ~generator(){};
};
struct A : public generator{
int operator()();
};
struct B : public generator{
int operator()();
};
int main()
{
auto v = std::vector<std::array<int, 500>>(2);
std::array<std::shared_ptr<generator>, 2> functors = {{std::make_shared<A>(),
std::make_shared<B>()}};
for (size_t i = 0; i < functors.size(); ++i)
std::generate(std::begin(v[i]), std::end(v[i]),
*(functors[i]));
return 0;
}
编译得到:
clang++ -std=c++11 -g -Wall -Wextra test_Whosebug.cpp
test_Whosebug.cpp:25:5: error: no matching function for call to 'generate'
std::generate(std::begin(v[i]), std::end(v[i]),*(functors[i]));
^~~~~~~~~~~~~
/usr/lib/gcc/i686-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_algo.h:5003:5: note: candidate template ignored: substitution
failure [with _ForwardIterator = int *, _Generator = generator]: parameter type 'generator' is an abstract class
generate(_ForwardIterator __first, _ForwardIterator __last,
是的,*(functors[i]) 的类型是生成器。这将不允许动态访问 A::operator() 和 B::operator()。我知道如何(从根本上)解决这个问题。例如
std::generate(std::begin(v[i]), std::end(v[i],
[&]{ return functors[i]->operator()(); };
然而,这似乎相当混乱,我正在寻找一种更清晰的方法来实现我的目标。
人们通常如何传递这样的动态函子。或者,如果这是不受欢迎的,最好的选择是什么?
欢迎任何帮助或建议。
您可能已经知道,问题在于 std::generate
按值获取生成器。要传递多态对象,必须按引用传递。
并且在 c++11 中有一个针对此类问题的解决方案(除了 lambda 选项,我相信它仍然比我们在 c++11 之前拥有的更优雅)。解决方案是std::ref。它 returns 一个可以按值传递的引用包装器。
这应该适合你:
std::generate(std::begin(v[i]), std::end(v[i]),
std::ref(*(functors[i])));
之所以可以将引用包装器作为仿函数传递,是因为它们实现了 operator()
我对 C++ 比较陌生,这是我第一次接触 post,所以请保持温和 ;-)
我了解如何传递函数指针或函数对象,就像许多 stl 函数所要求的那样。我不清楚如何将它与继承结合使用。
具体来说,我想用几个从基本仿函数继承的仿函数来调用一个 stl 函数。我没有找到关于这个主题的任何相关评论或最佳实践。这里有一个简化的代码片段:
struct generator{
virtual int operator()() = 0;
virtual ~generator(){};
};
struct A : public generator{
int operator()();
};
struct B : public generator{
int operator()();
};
int main()
{
auto v = std::vector<std::array<int, 500>>(2);
std::array<std::shared_ptr<generator>, 2> functors = {{std::make_shared<A>(),
std::make_shared<B>()}};
for (size_t i = 0; i < functors.size(); ++i)
std::generate(std::begin(v[i]), std::end(v[i]),
*(functors[i]));
return 0;
}
编译得到:
clang++ -std=c++11 -g -Wall -Wextra test_Whosebug.cpp
test_Whosebug.cpp:25:5: error: no matching function for call to 'generate'
std::generate(std::begin(v[i]), std::end(v[i]),*(functors[i]));
^~~~~~~~~~~~~
/usr/lib/gcc/i686-linux-gnu/4.6/../../../../include/c++/4.6/bits/stl_algo.h:5003:5: note: candidate template ignored: substitution
failure [with _ForwardIterator = int *, _Generator = generator]: parameter type 'generator' is an abstract class
generate(_ForwardIterator __first, _ForwardIterator __last,
是的,*(functors[i]) 的类型是生成器。这将不允许动态访问 A::operator() 和 B::operator()。我知道如何(从根本上)解决这个问题。例如
std::generate(std::begin(v[i]), std::end(v[i],
[&]{ return functors[i]->operator()(); };
然而,这似乎相当混乱,我正在寻找一种更清晰的方法来实现我的目标。
人们通常如何传递这样的动态函子。或者,如果这是不受欢迎的,最好的选择是什么?
欢迎任何帮助或建议。
您可能已经知道,问题在于 std::generate
按值获取生成器。要传递多态对象,必须按引用传递。
并且在 c++11 中有一个针对此类问题的解决方案(除了 lambda 选项,我相信它仍然比我们在 c++11 之前拥有的更优雅)。解决方案是std::ref。它 returns 一个可以按值传递的引用包装器。
这应该适合你:
std::generate(std::begin(v[i]), std::end(v[i]),
std::ref(*(functors[i])));
之所以可以将引用包装器作为仿函数传递,是因为它们实现了 operator()