2

我正在尝试为事件创建一个通用集合,以便它可用于不同类型的事件集。在使用可变参数模板时,我遇到了这个答案,这对我的示例有所帮助:

#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

给我一个“错误:无效使用无效表达式”。谁能告诉我,如何解决这个问题?

4

2 回答 2

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明确定义的顺序发生。

于 2013-02-17T19:07:36.193 回答
0

update_map是一个返回 void 的函数。

该行包括调用update_map,然后将返回值传递给gun

您不能将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);
}...);

这太棒了。

于 2013-02-17T19:08:44.073 回答