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

标签 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 expression is not an constant integral expression.

我可以这样做吗?

最佳答案

问题是 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对数组而不是指针进行操作:

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 ;事实上,问题在于静态常量数组不是编译时值,这与整型常量不同。所以我们回到了开始:除非value标记为 constexpr , 无法在常量表达式中使用它。

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

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

关于c++ - 我可以将编译时字符串比较与 MPL 模板混合使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10965079/

相关文章:

c++ - 浅拷贝到 Protocol Buffer 的字节字段

c++ - 在自建android中包含C++共享库。启动 ndk-build 时出错

boost - 根据 typedef 可以是 wcout 的通用 cout

c++ - 如何将 Parameter Pack 转换为 std::tuple 之外的其他内容?

c++ - 代码内联工作,但在类里面

python - 从 C++ 嵌入式解释器捕获 python 窗口输出

c++ - MPL替换而不类型转换聚变容器

c++ - 如何在 multi_index_container 中添加指定的有序唯一索引

c++ - 其他Boost Thread中的Boost调用方法