web-dev-qa-db-ja.com

テンプレートクラスを特定の組み込み型に制限するにはどうすればよいですか?

この問題は何度か議論されましたが、私が見つけたすべてのソリューションは機能しなかったか、またはboostの静的アサートに基づいていました。私の問題は簡単です。クラスがあり、実数型(doubleおよびfloat)のみを許可したい。 floatまたはdouble以外の型でクラスをインスタンス化しようとすると、コンパイルエラーが発生します。私はVisual C++ 11を使用しています。これが私が試したものです:

template <typename RealType>
class A
{
  // Warning C4346
  static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value);
}


template <typename RealType>
class A
{
  // Error C2062: type 'unknown' unexpected
  static_assert(decltype(RealType) == double || decltype(RealType) == float);
}

何か案は?前もって感謝します!

27
quant

私が見た1つの解決策は、std::enable_if型エイリアス。何かのようなもの:

using value_type = typename std::enable_if<
                    std::is_same<float, RealType>::value ||
                    std::is_same<double, RealType>::value,
                    RealType
                >::type;

value_typeは、RealTypefloatまたはdoubleである場合にのみ存在します。それ以外の場合、タイプは未定義であり、コンパイルは失敗します。

ただし、型に対して厳格すぎると警告します。テンプレートは、一部のテンプレートと同じくらい強力ですが、テンプレートを使用するダックタイピングは、テンプレートを使用する方法で使用できるすべてのタイプが機能することを意味します。型を禁止するために型を禁止しても、通常はあまり効果がなく、物事の柔軟性が低下する可能性があります。たとえば、ビッグ10進数型のように、より精度の高い型を使用することはできません。

21
cHao

最初の例では、static_assertは文字列リテラルになる2番目のパラメーターを使用する必要があります。それ以外の場合、失敗すると見なされます(edit: 2番目のパラメーターはC++ 17以降で有効です。そして、この2番目の引数はデフォルトにできません。

2番目の例は、いくつかの理由で正しくありません。

  • decltypeは、型ではなく式で使用するためのものです。
  • タイプを==と比較することはできません。これを行う正しい方法は、std::is_sameを使用した最初の試行で試すことです。

したがって、達成しようとしていることを行う正しい方法は次のとおりです。

#include <type_traits>

template <typename RealType>
class A
{
  static_assert(std::is_same<RealType, double>::value || std::is_same<RealType, float>::value,
                "some meaningful error message");
};

さらに、テンプレートを浮動小数点値に制限しようとしているに違いありません。これを行うには、特性 std::is_floating_point を使用できます。

#include <type_traits>

template <typename RealType>
class A
{
  static_assert(std::is_floating_point<RealType>::value,
                "class A can only be instantiated with floating point types");
};

ボーナスとして、 このオンライン例 を使用してください。

29
Morwenn

これにより、さまざまなタイプの特殊化も可能になります。

template<typename T, typename Enable = void>
class A {
/// Maybe no code here or static_assert(false, "Nice message");
};

/// This specialization is only enabled for double or float.
template<typename T>
class A<T, typename enable_if<is_same<T, double>::value || is_same<T, float>::value>::type> {

};
5
Juraj Blaho