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

「エラー:void式の無効な使用」が表示されます。誰かが私にこれを解決する方法を教えてもらえますか?

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)ことがわかりました。それはうまくいくはずです。これは次のように考えることができます。0gun

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_mapvoidを返す関数です。

その行は、 を呼び出してから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

これは、実行することをラムダにパッケージ化し、それらが渡されるために呼び出されます。

これにより、関数の必要性も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 に答える