7

可変個引数テンプレートのパラメーター パックに特定の型が含まれているかどうかを確認する組み込み機能が C++0x に用意されているかどうか疑問に思っていました。現在、適切な可変個引数テンプレートの代わりに boost::mpl::vector を使用している場合、boost:::mpl::contains を使用してこれを達成できます。ただし、コンパイル時間のオーバーヘッドが深刻です。C++0x には std::is_same に対するコンパイラ レベルのサポートがあると思います。そこで、以下のような一般化がコンパイラでもサポートされているかどうかを考えていました。

template <typename... Args, typename What>
struct is_present
{
  enum { value = (What in Args...)? 1 : 0 };
};
4

3 に答える 3

7

いいえ、次のようなコンパイル時の計算を行うには、可変個引数テンプレートで (部分的な) 特殊化を使用する必要があります。

#include <type_traits>

template < typename Tp, typename... List >
struct contains : std::true_type {};

template < typename Tp, typename Head, typename... Rest >
struct contains<Tp, Head, Rest...>
: std::conditional< std::is_same<Tp, Head>::value,
    std::true_type,
    contains<Tp, Rest...>
>::type {};

template < typename Tp >
struct contains<Tp> : std::false_type {};

可変個引数テンプレートの組み込み操作は他に 1 つだけあり、それはパラメーター リストの長さを計算する特殊な形式の sizeof 演算子です。

template < typename... Types >
struct typelist_len
{
   const static size_t value = sizeof...(Types);
};

ブースト mpl を使用すると、「コンパイル時間のオーバーヘッドが深刻です」というのはどこから得られますか? ここで仮定をしているだけではないことを願っています。Boost mpl は、単純なテンプレート メタプログラミングのように爆発するのではなく、遅延テンプレート インスタンス化などの手法を使用してコンパイル時間を短縮しようとします。

于 2010-01-23T00:15:44.070 に答える
2

手動の型再帰を回避したい場合std::common_typeは、可変引数テンプレートである STL で唯一のユーティリティであるように思われます。したがって、再帰を潜在的にカプセル化できる唯一のユーティリティです。


解決策 1

std::common_type型のセットから最小派生型を見つけます。数値を型で識別した場合、特に派生型の少ない数値を識別した場合、集合内で最大の数値が検出されます。次に、キー タイプと同等性を派生レベルにマッピングする必要があります。

using namespace std;

struct base_one { enum { value = 1 }; };
struct derived_zero : base_one { enum { value = 0 }; };

template< typename A, typename B >
struct type_equal {
 typedef derived_zero type;
};

template< typename A >
struct type_equal< A, A > {
 typedef base_one type;
};

template< typename Key, typename ... Types >
struct pack_any {
 enum { value =
     common_type< typename type_equal< Key, Types >::type ... >::type::value };
};


解決策 2

common_typeもう少しハッキングできます。基準は言う

特殊化の少なくとも 1 つのテンプレート パラメーターがユーザー定義型である場合、プログラムはこの特性を特殊化できます。

再帰的な部分特殊化のケース、二項演算子を適用するケース、および終端のケースです。基本的に、これは汎用fold関数であり、任意のバイナリ操作を追加できます。ここでは、OR よりも有益であるため、加算を使用しました。is_sameを返すことに注意してくださいintegral_constant

template< typename Addend >
struct type_sum { // need to define a dummy type to turn common_type into a sum
    typedef Addend type;
};

namespace std { // allowed to specialize this particular template
template< typename LHS, typename RHS >
struct common_type< type_sum< LHS >, type_sum< RHS > > {
    typedef type_sum< integral_constant< int,
     LHS::type::value + RHS::type::value > > type; // <= addition here
};
}

template< typename Key, typename ... Types >
struct pack_count : integral_constant< int,
 common_type< type_sum< is_same< Key, Types > > ... >::type::type::value > {};
于 2010-01-23T09:48:23.880 に答える