2017-08-23 12 views
0

次のコードでは、汎用的なテンプレートリストを取るGenericPublish__Advertise()を呼び出すより一般的な方法を探したいと思います。それを改善するために私は何ができますか?Variadicのテンプレート引数のマップ

私は特定の種類の発行者に話題をマッピングしたいと思います:

  • トピック[0] - >出版[0]
  • トピック[1] - >出版社[1]
  • など

GenericPublish__Advertise()のテンプレートバージョンを手作業で作成し、トピック[i]を手動でパブリッシャーにマップする必要があります。私は何とかGenericPublish__Advertise()の実装を一般化したいと思います。

事前に感謝します。

コード:

#include <iostream> 
    #include <memory> 
    #include <typeinfo> 
    #include <vector> 

    class AdvertiseOptionsBase { 
    public: 
     virtual const std::type_info &GetType() = 0; 
    }; 

    template <typename TSend> 
    class AdvertiseOptions : public AdvertiseOptionsBase { 
    public: 
     AdvertiseOptions(TSend opt) : opt_(opt) {} 
     const std::type_info &GetType() { return typeid(opt_); } 

    private: 
     TSend opt_; 
    }; 

    class Publisher { 
    public: 
     Publisher(const std::string &topic) : topic_(topic) {} 
     const std::string &GetTopic() const { return topic_; } 
     template <typename TSend> 
     void SetOptions(const AdvertiseOptions<TSend> &opt) { 
     options_ = std::make_unique<AdvertiseOptions<TSend>>(opt); 
     } 
     const std::unique_ptr<AdvertiseOptionsBase> &GetOptions() const { 
     return options_; 
     } 

    private: 
     std::string topic_; 
     std::unique_ptr<AdvertiseOptionsBase> options_; 
    }; 

    class Node { 
    public: 
     template <typename TSend> 
     Publisher advertise(std::string topic) { 
     Publisher publisher(topic); 
     TSend option; 
     AdvertiseOptions<TSend> options(option); 
     publisher.SetOptions<TSend>(options); 
     return publisher; 
     } 
    }; 

    template <typename TSend1, typename TSend2> 
    void GenericPublish__Advertise(Node &node, std::vector<Publisher> &publishers, 
            const std::vector<std::string> &topics) { 
     publishers.push_back(node.advertise<TSend1>(topics.at(0))); 
     publishers.push_back(node.advertise<TSend2>(topics.at(1))); 
    } 
    template <typename TSend1, typename TSend2, typename TSend3> 
    void GenericPublish__Advertise(Node &node, std::vector<Publisher> &publishers, 
            const std::vector<std::string> &topics) { 
     publishers.push_back(node.advertise<TSend1>(topics.at(0))); 
     publishers.push_back(node.advertise<TSend2>(topics.at(1))); 
     publishers.push_back(node.advertise<TSend3>(topics.at(2))); 
    } 

    template <typename... TSend> 
    class GenericPublish { 
    public: 
     GenericPublish(const std::vector<std::string> &topics) { 
     GenericPublish__Advertise<TSend...>(node_, publishers_, topics); 
     } 
     void PrintInfo() { 
     for (const auto &publisher : publishers_) { 
      std::cout << publisher.GetTopic() << " -----> " 
         << (publisher.GetOptions()->GetType()).name() << std::endl; 
     } 
     } 

    protected: 
     Node node_; 
     std::vector<Publisher> publishers_; 

    private: 
    }; 

    int main() { 
     std::vector<std::string> topics({"topic_int", "topic_double"}); 
     GenericPublish<int, double> o(topics); 
     o.PrintInfo(); 
     return 0; 
    } 
+0

'std :: index_sequence'を見てください。 – Rakete1111

答えて

3

ここでの典型的なアプローチは、index sequenceトリックを使用することです。あなたは種類のパラメータパックを取り、同じサイズのインデックス配列を構築して、両方を反復:

template <typename... TSends> // <== pack of types 
void GenericPublishAdvertise(Node &node, std::vector<Publisher> &publishers, 
          const std::vector<std::string> &topics) 
{ 
    GenericPublishAdvertiseImpl<TSends...>(node, publishers, topics, 
     std::index_sequence_for<TSends...>()); // <== index sequence creation 
} 

別の実施やって:

template <typename... TSends, size_t... Is> 
void GenericPublishAdvertiseImpl(Node &node, std::vector<Publisher> &publishers, 
    const std::vector<std::string> &topics, std::index_sequence<Is...>) 
{ 
    // since this is C++14 
    using swallow = int[]; 
    (void)swallow{0, 
     (void(publishers.push_back(node.advertise<TSends>(topics.at(Is)))), 0)... 
     }; 

    // in C++17, that's just 
    (publishers.push_back(node.advertise<TSends>(topics.at(Is))), ...); 
} 

は、そのパターンの説明についてはthis answerを参照してください。 。


GenericPublish__Advertiseを使用すると、UBであること:二重のアンダースコアで名前が予約されています。

2
template <class ... TSends, std::size_t ... Is> 
GenericPublish__Advertise_impl(Node &node, std::vector<Publisher> &publishers, 
           const std::vector<std::string>& topics, std::index_sequence<Is...>) 
{ 
    (void)int x[] = {(publishers.push_back(node.advertise<TSends>(topics.at(Is))), 0)...}; 
} 


template <class ... TSends> 
GenericPublish__Advertise((Node &node, std::vector<Publisher> &publishers, 
           const std::vector<std::string>& topics) 
{ 
    GenericPublish__Advertise_impl(node, publishers, topics, std::index_sequence_for<TSends...>{}); 
} 

あなたは可変引数パックを超えるインデックスのいくつかの種類をしたいときはかなり標準的なものであるここでは2つのトリックがあります。最初に、すべての引数とそれに加えてstd::index_sequence型を渡して、実装関数に委譲することです。これにより、実装関数は、0からN-1まで番号Nの整数パックをサイズNでパックすることができます。次に、未使用のダミー配列を初期化し、カンマ演算子を使用して、あなたは何をやっていますか?単に0を返します。

関連する問題