web-dev-qa-db-ja.com

テンプレートパラメータパックを展開せずに「保存」することは可能ですか?

この問題に出会ったとき、C++ 0x可変長テンプレートを試していました。

template < typename ...Args >
struct identities
{
    typedef Args type; //compile error: "parameter packs not expanded with '...'
};

//The following code just shows an example of potential use, but has no relation
//with what I am actually trying to achieve.
template < typename T >
struct convert_in_Tuple
{
    typedef std::Tuple< typename T::type... > type;
};

typedef convert_in_Tuple< identities< int, float > >::type int_float_Tuple;

GCC 4.5.0では、テンプレートパラメータパックをtypedefしようとするとエラーが発生します。

基本的に、パラメータパックを展開せずにtypedefに「保存」したいと思います。出来ますか?そうでない場合、これが許可されない理由はありますか?

72
Luc Touraille

別のアプローチは、Benのアプローチよりも少し一般的ですが、次のとおりです。

#include <Tuple>

template <typename... Args>
struct variadic_typedef
{
    // this single type represents a collection of types,
    // as the template arguments it took to define it
};

template <typename... Args>
struct convert_in_Tuple
{
    // base case, nothing special,
    // just use the arguments directly
    // however they need to be used
    typedef std::Tuple<Args...> type;
};

template <typename... Args>
struct convert_in_Tuple<variadic_typedef<Args...>>
{
    // expand the variadic_typedef back into
    // its arguments, via specialization
    // (doesn't rely on functionality to be provided
    // by the variadic_typedef struct itself, generic)
    typedef typename convert_in_Tuple<Args...>::type type;
};

typedef variadic_typedef<int, float> myTypes;
typedef convert_in_Tuple<myTypes>::type int_float_Tuple;

int main()
{}
56
GManNickG

許可されていない理由は、それが面倒だからだと思います。依存関係の反転を使用し、パラメーターパックを別のテンプレートに適用できるファクトリーテンプレートにパラメーターパックを保存する構造体を作成する必要があります。

以下のラインに沿ったもの:

template < typename ...Args >
struct identities
{
    template < template<typename ...> class T >
    struct apply
    {
        typedef T<Args...> type;
    };
};

template < template<template<typename ...> class> class T >
struct convert_in_Tuple
{
    typedef typename T<std::Tuple>::type type;
};

typedef convert_in_Tuple< identities< int, float >::apply >::type int_float_Tuple;
8
Ben Voigt

Ben Voigtのアイデアは、私自身の努力において非常に有用であることがわかりました。タプルだけでなく一般的なものにするために、少し変更しました。ここの読者にとって、それは明らかな修正かもしれませんが、示す価値があるかもしれません:

template <template <class ... Args> class T, class ... Args>
struct TypeWithList
{
  typedef T<Args...> type;
};

template <template <class ... Args> class T, class ... Args>
struct TypeWithList<T, VariadicTypedef<Args...>>
{
  typedef typename TypeWithList<T, Args...>::type type;
};

TypeWithListという名前は、タイプが以前のリストでインスタンス化されるという事実に由来します。

3
Werner Erasmus

これは、GManNickGのきちんとした部分的な特殊化トリックのバリエーションです。委任はありません。variadic_typedef構造体の使用を要求することにより、型の安全性が高まります。

#include <Tuple>

template<typename... Args>
struct variadic_typedef {};

template<typename... Args>
struct convert_in_Tuple {
    //Leaving this empty will cause the compiler
    //to complain if you try to access a "type" member.
    //You may also be able to do something like:
    //static_assert(std::is_same<>::value, "blah")
    //if you know something about the types.
};

template<typename... Args>
struct convert_in_Tuple< variadic_typedef<Args...> > {
    //use Args normally
    typedef std::Tuple<Args...> type;
};

typedef variadic_typedef<int, float> myTypes;
typedef convert_in_Tuple<myTypes>::type int_float_Tuple; //compiles
//typedef convert_in_Tuple<int, float>::type int_float_Tuple; //doesn't compile

int main() {}
2
jack