2012-06-09 41 views
3

我从另一个线程使用constexpr和C++ 11得到了这个编译时字符串比较(http://stackoverflow.com/questions/5721813/compile-time-assert-for-string-equality)。它的工作原理与常量字符串像“OK”我可以将编译时间字符串比较与MPL模板混合吗?

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

问题是mpl::c_strvalue成员未标记为constexpr。在图书馆作者决定包含对constexpr的支持之前,除非您愿意修改您的Boost代码(或创建您自己的c_str版本),否则您几乎已经搞错了。如果你决定这样做,修改很简单:你只需要找到BOOST_ROOT/boost/mpl/string.hpp并以此

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]; 

嗯,挖多一点之后,就更换该

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中;真正的问题是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)。我修改了上面的代码。

+0

嗨,吕克,感谢您的代码。 +1。 –

+0

我正在尝试代码,它现在看起来像static_assert现在工作。但BOOST MPL的示例代码失败: typedef boost :: mpl :: string <'hell','o wo','rld'> hello; typedef boost :: mpl :: push_back > :: type hello2; BOOST_ASSERT(0 == std :: strcmp(boost :: mpl :: c_str :: value,“hello world!“)); –

+0

它在连接时失败,说没有发现boost :: mpl :: string <'hell','o wo','rld'> –

相关问题