我可以将编译时字符串比较与 MPL 模板混合使用吗?
Can I mix compile time string comparison with MPL templates?
我从另一个使用 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表达式不是一个常量积分表达式。
我可以这样做吗?
问题是mpl::c_str
的value
成员没有标记为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
' '
};
通过这个
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
' '
};
};
// 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
;事实上,问题在于静态 const 数组不是编译时值,不像整数常量。所以我们回到了起点:除非value
被标记为constexpr
,否则没有办法在常量表达式中使用它。
至于为什么我最初给出的代码失败了,我现在无法回答,因为我的 gcc 版本 (4.6) 无法完全编译它......
更新 gcc 后,事实证明value
需要在类外部定义,即使它是在类中声明和初始化的(请参阅此问题)。我通过更正编辑了上面的代码。
- 混合组合和继承的C++问题
- 在混合代码库中将C转换为C++时出现许多包含错误
- D3D11-将混合权重和索引传递到顶点着色器
- C++分数混合比较运算符错误
- 将 Boost MPL 容器替换为 C++17 功能
- 是否可以混合使用SFINAE和模板专业化?
- 如何在 Python C++ 混合库中调试非确定性分段错误?
- 使用 Boost.Spirit 解析具有混合数据类型的 OBJ 文件?
- C++11 中的混合列表初始化
- C++以迭代方式搜索混合类型地图
- #pragma(*诊断)当将Clang分析器与GCC编译器混合时
- 混合 Rcpp 模块和 Rcpp::export
- C++/CLI 混合托管/本机 DLL 不起作用
- 在C++中混合覆盖和重载
- 关于 Direct3D9 中的 alpha 混合的问题
- 非推导上下文,如标准库中的"boost::mpl::identity:<T>:type"?
- 使用英特尔内部函数 (AVX) 中的混合说明
- C++ 中混合二进制/文本日志记录的最佳做法
- 我可以将编译时字符串比较与 MPL 模板混合使用吗?
- 用于创建混合类的 MPL 工厂方法