我正在尝试为事件创建一个通用集合,以便它可以重用于不同类型的事件集。在使用可变参数模板的同时,我遇到了THIS answer,这帮助了我的例子:
#include <boost/test/unit_test.hpp>
#include <string>
#include <unordered_map>
namespace
{
struct Event3 {
static const int event_type = 3;
int a;
};
struct Event5 {
static const int event_type = 5;
double d;
};
struct Event7 {
static const int event_type = 7;
std::string s;
};
template <class ...K>
void gun(K...) {}
template <class... Ts>
class EventCollection
{
template <typename T>
void update_map(std::unordered_map<int, size_t> & map, const T &)
{
BOOST_CHECK(map.find(T::event_type) == map.end());
map[T::event_type] = sizeof(T);
}
public:
std::unordered_map<int, size_t> curr_map;
EventCollection(Ts... ts)
{
gun(update_map(curr_map, ts)...); // will expand for each input type
}
};
} // namespace
BOOST_AUTO_TEST_CASE( test_01 )
{
Event3 x{13};
Event5 y{17.0};
Event7 z{"23"};
EventCollection<Event3, Event5, Event7> hoshi(x, y, z);
BOOST_CHECK_EQUAL(hoshi.curr_map.size(), 3);
}
然而,行
gun(update_map(curr_map, ts)...); // will expand for each input type
给我一个'错误:无效使用void表达式'。 任何人都能告诉我,如何解决这个问题?
答案 0 :(得分:4)
问题是您的update_map
会返回void
。因此你不能这样写:
gun(update_map(curr_map, ts)...);
因为update_map
的返回值应该作为参数传递给gun
。
修复是将某些内容传递给gun
作为参数,因此您可以执行此操作:
gun( (update_map(curr_map, ts),0)...);
现在表达(update_map(curr_map, ts),0)
原来是0
,它作为参数传递给gun
。这应该工作。您可以将其视为:
T argmument = (update_map(curr_map, ts),0); //argument is 0, and T is int
-
另外,正如另一个答案所指出的那样,对gun()
的参数的评估顺序是未指定的(意味着调用函数update_map
的顺序,未指定),这可能导致不希望的结果。另一种解决方案已经解决了这个问题。这是另一个(这有点棘手和容易!):
//ensure that the size of the below array is at least one.
int do_in_order[] = {0, (update_map(curr_map, ts),0)...};
因为数组元素的初始化顺序是明确定义的(从左到右),所以现在对update_map
的所有调用都按照明确的顺序进行。
答案 1 :(得分:0)
update_map
是一个返回void的函数。
该行包括调用update_map
,然后将返回值传递给gun
。
您无法将void
返回值传递给其他函数。
因此“无效使用void表达式”。
有很多方法可以解决此问题,包括让update_map
返回struct empty {};
请注意,您的代码会导致update_map
的调用以未指定的顺序发生。这很容易导致意外行为。
我可以建议:
void do_in_order();
template<typename F0, typename... Functors>
void do_in_order( F0&& f0, Functors&& funcs... ) {
f0();
do_in_order( std::forward<Functors>(funcs)... );
}
然后将调用替换为gun
:
do_in_order([&]{update_map(curr_map, ts);}...); // will expand for each input type
将要做的事情打包成lambdas,然后调用它们以便传递它们。
现在,这也完全取消了对update_map
功能的需求:
do_in_order([&]{
BOOST_CHECK(curr_map.find(ts::event_type) == curr_map.end());
map[ts::event_type] = sizeof(ts);
}...);
太棒了。