文字ではなく整数型に対して何かをしたいとします。
is_integral<T>::type
とis_char<T>::type
これを書くことは可能ですか:
integral_constant<bool,is::integral<T>::value && !is_char<T>::value>
より読みやすい
この種のメタ計算は C++11 よりも前から行われており、Boost.MPLは C++03 の TMP の重砲です。これにより、要件は次のように表現できます。
// in C++03:
// typedef /* compute */ result;
using result = and_<is_integral<T>, not_<is_char<T>>>;
(and_
とnot_
はboost::mpl
名前空間からのものです。)
::value
ボイラープレートを使用する必要がないため、冗長性が制限されていることに注意してください。同様に、は怠惰であり、結果を ( orになる) または(まあ、型になる - ドキュメントにすべての詳細が記載されています) のresult
いずれかで結果を強制的に計算できます。ただし、Boost.MPL を使用すると、これを簡単に行うことができます。たとえば、ロジックを反転するのに十分ですが、機能します。依存している場合は追加が必要であることを考えると良いことです。result::value
true
false
result::type
not_<result>
not_<result::type>
typename
result
Boost.MPL は可変個引数テンプレートをエミュレートするため、C++03 で非常に役立つと考えています。たとえば、and_
は 2 つの引数に制限されません。私は C++11 ではそれを避けてきましたが、これを使用したほとんどの状況でパック展開を使用するようになったからです。ただし、任意の式 (論理演算子を含む式など) でパックを展開することはできないため、のようなものand_
は依然として有用です。&&
これは、論理メタ関数でのみ実行できます。
// Enforce precondition: every type T must be integral
static_assert( and_<std::is_integral<T>...>::value, "Violation" );
この記事は、メタ計算の冗長性を減らすための良いヒントを提供する良い読み物だと思います。汎用プログラミングに使用される SFINAE に焦点を当てていますが、TMP にも適用できます (SFINAE は TMP でも使用できます)。最後の例は
template <typename T,
EnableIf<is_scalable<T>, is_something_else<T>>...>
T twice(T t) { return 2*t; }
Boost で提供されるものと同様の機能を使用すると、C++03 では次のようになります。
template<typename T>
typename enable_if<
and_<is_scalable<T>, is_something_else<T>>
, T
>::type twice(T t) { return 2*t; }
単純な C++11 バージョンは間違いなく最悪に見えます。
template<typename T>
typename std::enable_if<
is_scalable<T>::value && is_something_else<T>::value
, T
>::type twice(T t) { return 2*t; }
Boost.MPL のスタイルから離れて、値とconstexpr
関数の使用に向けて型と型を「返す」メタ関数を優先することを提唱する人を見てきました。これは次のようになります。
// EnableIf alias now accepts non-type template parameters
template<typename T
, EnableIf<is_scalable<T>() && is_something_else<T>()>...>
T twice(T t) { return 2*t; }
ただし、がパックのconstexpr
場合は、論理和などを計算する関数が必要です。T...
EnableIf<any(is_foo<T>()...)>
なぜ整数定数が必要なのですか? コンパイル時の定数 bool だけが必要な場合は、式をラップする必要はありません。
is_integral<T>::value && !is_char<T>::value
この式がいくつかの場所で必要な場合は、独自の特別な型特性を記述するだけです。
template<typename T>
struct is_integral_and_not_char {
static const bool value = is_integral<T>::value && !is_char<T>::value;
};
is_integral_and_not_char<T>::value
または、UnaryTypeTrait の概念に準拠したい場合は、
template<typename T>
struct is_integral_and_not_char
: std::integral_constant<bool, std::is_integral<T>::value && !std::is_char<T>::value>
{}