2017-01-13 12 views
2

ClassTypeとそのコンストラクタ引数をテンプレート引数として受け取るオブジェクト作成者クラスを作成したいと思います。空tupleからstd::get<0>を避けるために、守ってstd::enable_ifバリデーションテンプレートの存在に基づくstd :: enable_if

template<typename ClassType, typename ... Args> 
class ClassCreator : public ClassType 
{ 
    std::tuple<Args ...> args_; 
public: 
    template <typename std::enable_if<sizeof...(Args)!=0>::type> 
    ClassCreator(Args ... args) : args_(std::make_tuple(args ...)), ClassType(args ...){} 

    template <typename std::enable_if<sizeof...(Args)==0>::type> 
    ClassCreator() : ClassType(){} 

    template <typename std::enable_if<sizeof...(Args)!=0>::type> 
    ClassType getObject() const 
    { 
     return ClassType(std::get<sizeof...(Args)>(args_) ...); 
    } 

    template <typename std::enable_if<sizeof...(Args)==0>::type> 
    ClassType getObject() const 
    { 
     return ClassType(); 
    } 
}; 

基本的に私のコードは次のようになります。

class A 
{ 
public: 
    A(){} 
    A(int firstInt, int secondInt){} 
}; 

int main() 
{ 
    ClassCreator<A> creatorATrivial(); 
    ClassCreator<A, int, int> creatorA(1, 2); 
    A aTrivial = creatorATrivial.getObject(); 
    A a = creatorA.getObject(); 
} 

をそして私は、エラーのトンを得る:

私は、サンプルクラスとそれを使用しています。 sizeof...オペレータが正しく理解していますか? tupleを開梱するにはstd::get<sizeof...(Args)>(args_) ...が有効ですか?

答えて

3

問題はSFINAEが置換即時コンテキストにのみN OT N E rrorであることです。あなたの例では、ここで:置換はすぐに実行され、instiated機能がenable_if<true>::typeまたはenable_if<false>::typeのいずれかになります、後者は病気に形成されているように、

template<typename ClassType, typename ... Args> 
class ClassCreator : public ClassType 
{ 
    template <typename std::enable_if<sizeof...(Args)!=0>::type> 
    ClassCreator(Args ... args) 

Args...は、コンストラクタの即時コンテキストではありません。

また、この:

return ClassType(std::get<sizeof...(Args)>(args_) ...); 

が悪い形成されています。 2番目の...には展開するパックがありません。これを回避する一般的な方法は、インデックスシーケンストリックです。

return std::apply([](auto const&... elems){ return ClassType(elems...); }, 
    args_); 

引数を格納し、それらを渡すためにクラスのクリエイターを行う最も簡単な方法は、次のようになります:

C++ 17で、我々はこの場合にもなり std::applyを、持っています
template <class T> 
class ClassCreator { 
    std::function<T()> creator; 

public: 
    // as improvements, add perfect forwarding 
    template <class... Args, 
     std::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> 
    ClassCreator(Args... args) { 
     creator = [=]{ return T(args...); }; 
    } 

    T getObject() const { 
     return creator(); 
    } 
}; 

ClassCreator<A> creatorATrivial(); 
ClassCreator<A> creatorA(1, 2); // no <int, int> necessary 
A aTrivial = creatorATrivial.getObject(); 
A a = creatorA.getObject(); 
関連する問題