2017-11-11 11 views
0

私は、さまざまな数のテンプレートパラメータを持つstd :: functionオブジェクトを受け入れるか、まったく受け付けない、可変長のテンプレートメンバー関数を実装しようとしています。バリッドテンプレートをstd :: type_indexのマップのキーとして使用するには?

以下は、私が試みているものの簡略化されコンパイル可能な例です。私は動的に任意のユーザー定義のデータオブジェクトを私のマネージャに追加できるようにしたい。次に、可変的なテンプレートを使用してマネージャー内に格納されているデータ型のいずれかを反復処理できるようにしたいと考えています。私は// HowToにコメントしましたか? //私が執着しているものです。バリデーショナルテンプレートを使用してコメントアウトされたコードを実装する方法は?

私はこのポストから解決策を導き出すためにしようとしています: Possible Solution?

#include <functional> 
#include <map> 
#include <memory> 
#include <typeindex> 
#include <vector> 

constexpr auto Count = 10; 

struct Base 
{ 
    virtual ~Base() 
    { 
    } 
}; 

template <typename T> 
struct Container : public Base 
{ 
    std::vector<T> data; 
    std::vector<bool> valid; 
}; 

struct Manager 
{ 
    template <typename T> 
    void add() 
    { 
     Container<T>* container{}; 

     if(this->containers[typeid(T)] == nullptr) 
     { 
      auto c = std::make_unique<Container<T>>(); 
      container = c.get(); 
      this->containers[typeid(T)] = std::move(c); 
     } 
     else 
     { 
      container = static_cast<Container<T>*>(this->containers[typeid(T)].get()); 
     } 

     container->data.push_back(T()); 
     container->valid.push_back(true); 
    } 

    template <typename ...Args> 
    void each(std::function<void(Args&...)> f) 
    { 
     // HowTo? // auto oneContainer = static_cast<Container<T>*>(this->containers[typeid(DataOne)].get()); 
     // HowTo? // auto twoContainer = static_cast<Container<T>*>(this->containers[typeid(DataTwo)].get()); 

     for(auto i = 0; i < Count; i++) 
     { 
      // HowTo? // if(oneContainer->valid[i] == true && twoContainer->valid[i] == true) 
      // HowTo? // f(oneContainer->data[i], twoContainer->data[i]); 
     } 
    } 

    std::map<std::type_index, std::unique_ptr<Base>> containers; 
}; 

struct DataOne 
{ 
    int value{}; 
}; 

struct DataTwo 
{ 
    double value{}; 
}; 

int main() 
{ 
    Manager manager; 

    for(auto i = 0; i < Count; i++) 
    { 
     manager.add<DataOne>(); 
     manager.add<DataTwo>(); 
    } 

    manager.each<DataOne>([](DataOne& a) { 
     a.value = 0; 
    }); 

    manager.each<DataTwo>([](DataTwo& a) { 
     a.value = 0.0; 
    }); 

    manager.each<DataOne, DataTwo>([](DataOne& a, DataTwo& b) { 
     a.value = 0; 
     b.value = 0.0; 
    }); 
} 

答えて

2
auto containers = std::make_tuple<Container<Args>*...>(
    static_cast<Container<Args>*>(this->containers[typeid(Args)].get())... 
); 

...

for(auto i = 0; i < Count; i++) 
    { 
     std::apply([&f](auto*... containers){ 
     bool valid = (containers&&...) && (containers->valid[i]&&...); 
     if (valid) 
      f(containers->data[i]...); 
     }, containers); 
    } 

タイプミスを許しなさい。

+0

ありがとうございました!これはまさに私が望んでいたものです。私はstd :: apply()が存在するかどうか分からなかった。私はC++の17の機能についてもっと読む必要があります。私の唯一の問題は、私のコンパイラがMSVC 15.4.3であり、折り畳み式をまだサポートしていないようです。しかし、それはMSVC 15.5でサポートされるように見えます! – ASxa86

+0

@ asxa86 'auto tests = {true、(コンテナ&&コンテナ - > value [i])...}を試してください; bool valid = all_of(tests.begin()、tests.end()); ' – Yakk

+0

それはうまくいくようです、ありがとうございます。 – ASxa86

関連する問題