2

これを確認することは可能ですか?

template<class IntType,IntType value>
struct X{};

IntTypeこれが意味するのは、ユーザーによって提供された値が(std整数型のいずれかである可能性がある)型に「適合する」ことを確認することは可能ですか?たとえば、次のようなものを検出したいと思います。

X<char,300> a;//here 300 is out of range and I would like to be able to detect that.
4

5 に答える 5

2

Xの署名を元の編集されていない質問の場合と同じように変更したので、 Boostを使用して簡単に実装できます。整数

#include <boost/static_assert.hpp>
#include <boost/cstdint.hpp>
#include <boost/integer_traits.hpp>

template<
    typename IntType,
    boost::uint64_t Value,
    bool IsSigned = boost::integer_traits<IntType>::is_signed
>
struct validate_range;

template<typename IntType, boost::uint64_t Value>
struct validate_range<IntType, Value, true>
{
    typedef boost::integer_traits<IntType> traits_t;
    static bool const value =
        static_cast<boost::int64_t>(Value) >= traits_t::const_min &&
        static_cast<boost::int64_t>(Value) <= traits_t::const_max;
};

template<typename IntType, boost::uint64_t Value>
struct validate_range<IntType, Value, false>
{
    typedef boost::integer_traits<IntType> traits_t;
    static bool const value =
        Value >= traits_t::const_min &&
        Value <= traits_t::const_max;
};

template<typename IntType, boost::uint64_t Value>
struct X
{
    BOOST_STATIC_ASSERT_MSG(
        (validate_range<IntType, Value>::value),
        "Value constant is out of range"
    );
};

int main()
{
    X<char, -2> x1;             // fails iif char is unsigned by default
    X<char, 2> x2;              // fine
    X<char, 255> x3;            // fails iif char is signed by default
    X<unsigned char, -2> x4;    // fails
    X<unsigned char, 255> x5;   // fine
    X<unsigned char, 300> x6;   // fails
}
于 2011-04-05T19:06:46.080 に答える
2

Boostは正しい方法ですが、本当に必要なのは、新しいC++0x標準である静的アサートです。Boostはすでにboost_staticassertに実装しています。

于 2011-04-05T18:39:13.920 に答える
1

いいえ。あなたのコードを考えると、あなたがそれを見る前に、コンパイラによってに300変換されます。char

最も近い方法は、範囲がターゲットタイプよりも大きい整数パラメーターに引数を受け入れることです。次に、変換する前に値が適合することを確認します。唯一の問題はsignedunsignedですが、一般的な解決策はないと思います。

しかし、心配しないでください。引数が正しく提供されていることを確認するのはクラスの仕事ではありません。それは、単に存在しないユーティリティタイプの仕事になります。良くも悪くも、C ++は、プログラマーがこれらの間違いを犯さないことを前提としているため、このためのクリーンなメカニズムを提供しません。

于 2011-04-05T18:51:38.713 に答える
0

この質問の直接的な解決策は次のようになります。

   template< typename T, T X, T L, T H>
      using inside_t = 
        std::enable_if_t< (X <= H) && (X >= L), 
           std::integral_constant<T, X> >;

OPに適用:

    template<typename C, unsigned K>    struct X; // final {};

template<unsigned K>
struct X<char, K> final 
{
    using ascii_ordinal = inside_t<unsigned, K, 0, 127>;
    char value = char(ascii_ordinal::value);
};

それが仕事をするとき、これは本当にひどいCLエラーメッセージをレンダリングします:

X<char, 300> a; //here 300 is out of range and I would like to be able to detect that.

あまり洗練されていませんが、最も快適なAPIは次のようになります。

template<unsigned K>
struct X<char, K> final 
{
    static_assert( K >= 0U && K <= 127U, "\n\nTeribly sorry, but value must be between 0 and 127 inclusive\n\n") ;
    char value = char(K);
};
于 2019-03-04T08:42:24.020 に答える
0

C++20ではstd::in_range

if constexpr (std::in_range<char>(300)) {
    // ...
}

自分で比較するintcmpもあります

int val = 300;
if constexpr (std::cmp_greater(val, std::numeric_limits<char>::max()))
{
    std::cout << "Overflow\n";
}
else if constexpr (std::cmp_less(val, std::numeric_limits<char>::min()))
{
    std::cout << "Underflow\n";
}
else
{
    std::cout << "In range\n";
}
于 2021-07-31T16:54:58.920 に答える