我可以将编译时字符串比较与MPL模板混合使用吗?

时间:2012-06-09 22:36:04

标签: c++ boost boost-mpl

我使用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表达式的编译错误不是一个常量的整数表达式。

我可以这样做吗?

1 个答案:

答案 0 :(得分:1)

问题是value的{​​{1}}成员未标记为mpl::c_str。在图书馆作者决定包含对constexpr的支持之前,除非您愿意修改Boost代码(或创建自己的constexpr版本),否则您将非常困惑。如果您决定这样做,修改非常简单:您只需找到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'
};

嗯,经过多挖一点后,事实证明这个问题比我想象的要复杂得多。实际上,静态常量可以用在constexpr中;真正的问题是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,它在数组而不是指针上运行:

isequal

不幸的是,此代码不适用于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"); ;事实上,问题是静态const数组不是编译时值,不像积分常量。所以我们回到了开头:除非mpl::c_str被标记为value,否则无法在常量表达式中使用它。

至于我最初给出的代码失败的原因,我现在无法回答我的gcc版本(4.6)fails to compile it altogether ......

更新gcc后,事实证明constexpr需要在类外定义,即使它在类中声明和初始化(参见this question)。我通过修正编辑了上面的代码。