3

constexpr と C++11 (http://stackoverflow.com/questions/5721813/compile-time-assert-for-string-equality) を使用して、別のスレッドからこのコンパイル時の文字列比較を取得しました。「OK」のような定数文字列で動作します

    constexpr bool isequal(char const *one, char const *two) {
        return (*one && *two) ? (*one == *two && isequal(one + 1, two + 1))
        : (!*one && !*two);
    }

次のコンテキストで使用しようとしています。

 static_assert(isequal(boost::mpl::c_str<boost::mpl::string<'ak'>>::value, "ak"), "should not fail");

しかし、 static_assert 式は定数整数式ではないというコンパイルエラーが発生します。

これはできますか?

4

1 に答える 1

1

問題は、 のvalueメンバーがmpl::c_strとしてマークされていないことconstexprです。ライブラリの作成者が のサポートを含めることを決定するまではconstexpr、Boost コードを変更する (または独自のバージョンの を作成する) つもりがない限り、かなりうんざりしていますc_str。そうすることにした場合、変更は非常に簡単です。BOOST_ROOT/boost/mpl/string.hppこれを見つけて置き換えるだけです。

template<typename Sequence>
struct c_str
{
    ...
    static typename Sequence::value_type const value[BOOST_MPL_LIMIT_STRING_SIZE+1] 
};

template<typename Sequence>
typename Sequence::value_type const c_str<Sequence>::value[BOOST_MPL_LIMIT_STRING_SIZE+1] =
{
    #define M0(z, n, data)                                                                      \
    mpl::aux_::deref_unless<BOOST_PP_CAT(i, n), iend>::type::value,
    BOOST_PP_REPEAT(BOOST_MPL_LIMIT_STRING_SIZE, M0, ~)
    #undef M0
    '\0'
};

これで

template<typename Sequence>
struct c_str
{
    ...
    static constexpr typename Sequence::value_type value[BOOST_MPL_LIMIT_STRING_SIZE+1] =
    {
        #define M0(z, n, data)                                                                      \
        mpl::aux_::deref_unless<BOOST_PP_CAT(i, n), iend>::type::value,
        BOOST_PP_REPEAT(BOOST_MPL_LIMIT_STRING_SIZE, M0, ~)
        #undef M0
        '\0'
    };
};

// definition still needed
template<typename Sequence>
constexpr typename Sequence::value_type c_str<Sequence>::value[BOOST_MPL_LIMIT_STRING_SIZE+1];

うーん、もう少し掘り下げてみると、問題は思ったよりも複雑であることがわかりました。実際、静的定数は constexpr で使用できます。本当の問題は、それc_str<T>::valueが配列であり、関数がパラメーターとしてポインターを取ることです。結果として、コンパイラは配列を減衰させる必要があります。これは、最初の要素のアドレスを取得することになります。アドレスは実行時の概念であるため、constexpr でオブジェクトのアドレスを取得することはできません。

isequalこの問題を解決するために、ポインターではなく配列で動作するの 2 番目のバージョンを作成しようとしました。

template <int N, int M>
constexpr bool isequal(char const (&one)[N], char const (&two)[M], int index)
{
    return (one[index] && two[index]) ?
        (one[index] == two[index] && isequal(one, two, index + 1)) :
        (!one[index] && !two[index]);
}

template <int N, int M>
constexpr bool isequal(char const (&one)[N], char const (&two)[M])
{
    // note: we can't check whether N == M since the size of the array
    // can be greater than the actual size of the null-terminated string
    return isequal(one, two, 0);
}

constexpr char hello[] = "hello";
static_assert(isequal(hello, hello), "hello == hello");
constexpr char zello[] = "zello";
static_assert(!isequal(hello, zello), "hello != zello");
constexpr char hel[] = "hel";
static_assert(!isequal(hello, hel), "hello != hel");

残念ながら、このコードは では機能しませんmpl::c_str。実際、問題は、整数定数とは異なり、静的 const 配列がコンパイル時の値ではないことです。valueが とマークされていない限りconstexpr、定数式で使用する方法はありません。

最初に提供したコードが失敗した理由については、私のバージョンの gcc (4.6)では完全にコンパイルできないため、今は答えられません...

gcc を更新した後value、クラスで宣言および初期化されていても、クラスの外部で定義する必要があることがわかりました (この質問を参照してください)。上記のコードを修正して編集しました。

于 2012-06-11T15:38:39.027 に答える