【问题标题】:Can I mix compile time string comparison with MPL templates?我可以将编译时字符串比较与 MPL 模板混合使用吗?
【发布时间】:2012-06-09 22:36:03
【问题描述】:

我从另一个线程使用 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 integer expression。

我可以这样做吗?

【问题讨论】:

    标签: c++ boost boost-mpl


    【解决方案1】:

    问题是mpl::c_strvalue 成员没有标记为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&lt;T&gt;::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;实际上,问题在于静态 const 数组不是编译时值,这与整数常量不同。所以我们又回到了起点:除非value 被标记为constexpr,否则无法在常量表达式中使用它。

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

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

    【讨论】:

    • 我正在尝试代码,看起来 static_assert 现在可以工作了。但是BOOST MPL的示例代码失败: typedef boost::mpl::string hello; typedef boost::mpl::push_back >::type hello2; BOOST_ASSERT(0 == std::strcmp(boost::mpl::c_str::value, "hello world!"));
    • 链接时间失败说 boost::mpl::string is not found
    • 好的,我更新了gcc,我认为问题是即使value在类中初始化,仍然需要在外面定义(见this question。我在里面编辑了代码我的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-16
    • 2018-01-18
    相关资源
    最近更新 更多