2016-04-16 4 views
4

可変数の型を引数として受け入れるテンプレートクラスがあります。コンストラクタは、パラメータ型としてArgs... - 1を使用するクラスのインスタンスへのポインタを受け取ります。インターネット上で検索すると、このタイプの問題を処理するためにstd::tupleがよく使用されることがわかりましたが、テンプレート引数を取り、タプルを作成し、最後の型を削除してから再度タプルを展開して保存しますその結果は後でparent()関数で取り出すことができる変数になります。変数の型として最後の1つを除くすべての可変テンプレート引数を展開します

template<typename ...Args> 
class MyClass 
{ 
public: 
    MyClass(MyClass<Args...> *parent) : parent_(parent) // Should be Args - 1 
    { 
    } 

    MyClass<Args...>* parent() 
    { 
     return parent_; 
    } 

private: 
    MyClass<Args...> *parent_; 
}; 

タプルを含む類似のトピックについて、私はここでさまざまな答えをStackOverflowで見つけました。このコードは別の質問に投稿されており、最後のものを除くすべてのパラメータを含むタプルを取得する必要があります。問題は、そのタプルを再び解凍するためにそれをどのように適応させるべきかわかりません。

template<typename, typename> 
struct concat_tuple { }; 

template<typename... Ts, typename... Us> 
struct concat_tuple<std::tuple<Ts...>, std::tuple<Us...>> 
{ 
    using type = std::tuple<Ts..., Us...>; 
}; 

template <class T> 
struct remove_last; 

template <class T> 
struct remove_last<std::tuple<T>> 
{ 
    using type = std::tuple<>; 
}; 

template <class T, class... Args> 
struct remove_last<std::tuple<T, Args...>> 
{ 
    using type = typename concat_tuple<std::tuple<T>, typename remove_last<std::tuple<Args...>>::type>::type; 
}; 
+0

あなたのコードですべてのことが可能です(Argsのコメントを外している限り)。作成者のメソッドを公開していない可能性があります。デフォルトのクラスメンバアクセス修飾子はprivateです... –

+0

@WojciechFrohmberg OPは 'remove_last :: type'からタプルを解く方法を知らない –

+0

@WojciechFrohmbergコメントArgsは単にタイプミスでした:D – Stefano

答えて

5
#include <type_traits> 
#include <tuple> 
#include <utility> 
#include <cstddef> 

template <template <typename...> class C, typename... Args, std::size_t... Is> 
auto pop_back(std::index_sequence<Is...>) noexcept 
    -> C<std::tuple_element_t<Is, std::tuple<Args...>>...>&&; 

template <typename... Args> 
class MyClass 
{ 
    using Parent = std::remove_reference_t< 
         decltype(pop_back<::MyClass, Args...>(std::make_index_sequence<sizeof...(Args) - 1>{})) 
        >; 

public:  
    explicit MyClass(Parent* parent) : parent_(parent) 
    { 

    } 

    Parent* parent() 
    { 
     return parent_; 
    } 

private: 
    Parent* parent_; 
}; 

template <> 
class MyClass<> {}; 

int main() 
{ 
    MyClass<> a; 
    MyClass<int> b(&a);  
    MyClass<int, char> c(&b); 
    MyClass<int, char, float> d(&c); 
} 

DEMO


前の質問のための答え、編集前:

#include <tuple> 
#include <utility> 
#include <cstddef> 

template <typename... Args> 
class MyClass 
{ 
public:  
    auto newInstance() 
    { 
     return newInstance(std::make_index_sequence<sizeof...(Args) - 1>{}); 
    } 

private:   
    template <std::size_t... Is> 
    MyClass<typename std::tuple_element<Is, std::tuple<Args...>>::type...> newInstance(std::index_sequence<Is...>) 
    { 
     return {}; 
    } 
}; 

DEMO 2


なぜpop_back関数にボディがないのですか?

これは実際には機能宣言の観点から実装された特性です。また、あなたは、構造専門でより多くの古典的なソリューションを使用することができます。その後、

template <typename T, typename S> 
struct pop_back; 

template <template <typename...> class C, typename... Args, std::size_t... Is> 
struct pop_back<C<Args...>, std::index_sequence<Is...>> 
{ 
    using type = C<std::tuple_element_t<Is, std::tuple<Args...>>...>; 
}; 

とは使用:

ある
using Parent = typename pop_back<MyClass, std::make_index_sequence<sizeof...(Args) - 1>>::type; 

が、私は構文を短くする関数宣言を使用しました。誰も評価されたコンテキストでこの関数を呼び出すはずがないので、ボディは必要ありません。

なぜnoexceptを使用していますか?

あなたが機能してい想像:

void foo(MyClass<int, char>) noexcept {} 

そして、他の場所で通話がnoexceptあるかどうかを確認したい:noexcept指定がなければ

static_assert(noexcept(foo(pop_back<MyClass, int, char, float>(std::index_sequence<0, 1>{}))), "!"); 

を、上記アサーションは失敗し、 pop_backへの呼び出しはおそらくコードを投げるものとみなされるからです。

+0

素敵な答えをありがとう、それは動作します。しかし、私自身のコードで苦労した後、私のコードの最近の変更を反映するために質問を編集しなければなりませんでした。ご覧のとおり、クラスの新しいインスタンスを作成する必要はありませんが、代わりにコンストラクタパラメータとして渡す必要があり、メンバー変数として保存する必要があります。 – Stefano

+0

@Stefano更新 –

+0

これは完璧に動作します、ありがとうございます。なぜコードが何をしているのか、さらに2つの質問を説明してください:なぜpop_back関数にはボディがないのですか、なぜnoexceptを使用していますか? – Stefano

関連する問題