Constexpr查找实现
Constexpr find implementation
在回答了这个问题,阅读了这个演讲,看了这个代码之后,我想用一个简单的数组类来实现constexpr find
。
考虑下面的例子:
#include <cstddef>
template <class It, class T>
constexpr auto constexpr_find(const It& b, const It& e, T value) {
auto begin = b;
while (begin != e) {
if (*begin == value) break;
++begin;
}
return *begin;
}
template<typename T, size_t N>
class array
{
public:
typedef T* iterator;
typedef const T* const_iterator;
constexpr auto begin() const { return const_iterator(array_); }
constexpr auto end() const { return const_iterator(array_ + N); }
T array_[N];
static constexpr size_t size = N;
};
int main()
{
constexpr array<int, 3> array{{0,2,3}};
static_assert(constexpr_find(array.begin(), array.end(), 0) == 0, "");
}
按预期编译
和自定义constexpr迭代器:
template<class T>
class array_iterator
{
public:
constexpr array_iterator(const T* v) : iterator(v)
{
}
constexpr const T& operator * () const { return *iterator; }
constexpr array_iterator& operator ++()
{
++iterator;
return *this;
}
constexpr bool operator != (const array_iterator& other) const { return iterator != other.iterator; }
private:
const T* iterator;
};
在数组中:
typedef const array_iterator<const T> const_iterator;
这是唯一的区别,编译器给我错误:
的constexpr展开中的
constexpr_find<array_iterator<const int>, int>(array.array<T, N>::begin<int, 3u>(), array.array<T, N>::end<int, 3u>(), 0)
error:
(((const int*)(& array.array<int, 3u>::array_)) != (((const int*)(& array.array<int, 3u>::array_)) + 12u))
不是常数表达
生活例子
这是gcc bug,因为clang编译得很好,还是两个片段有区别?
我不能确定,但是您将数组成员的指针存储到外部迭代器类中,这可能是导致该错误的原因。
--------- update start ---------
下面是演示这个问题的最小代码片段:constexpr const struct A { int i[2]; } a {{0,0}};
int main ()
{
static_assert (nullptr != a.i , ""); // ok
static_assert (nullptr != a.i+0, ""); // ok
static_assert (nullptr != a.i+1, ""); // error
}
在常量表达式中,指针指向数组元素(偏移量非零)似乎是被禁止的。
--------- update end ---------
解决方法很简单——存储指向数组对象的指针和偏移量。
生活#include <cstddef>
template <class It, class T>
constexpr auto constexpr_find(const It& b, const It& e, T value) {
auto begin = b, end = e;
while (begin != end) {
if (*begin == value) break;
++begin;
}
return *begin;
}
template<class Array>
class array_iterator
{
public:
constexpr array_iterator(const Array& a, size_t pos=0u) : array_(&a), pos_ (pos)
{
}
constexpr const typename Array::value_type&
operator * () const { return (*array_)[pos_]; }
constexpr array_iterator& operator ++()
{
++pos_;
return *this;
}
constexpr bool operator != (const array_iterator& other) const
{ return array_ != other.array_ || pos_ != other.pos_; }
private:
const Array* array_;
size_t pos_;
};
template<typename T, size_t N>
class array
{
public:
typedef T value_type;
typedef const array_iterator<array> const_iterator;
constexpr T const& operator[] (size_t idx) const { return array_[idx]; }
constexpr auto begin() const { return const_iterator(*this); }
constexpr auto end() const { return const_iterator(*this, N); }
T array_[N];
static constexpr size_t size = N;
};
int main()
{
constexpr array<int, 3> array{{0,2,3}};
static_assert(constexpr_find(array.begin(), array.end(), 0) == 0, "");
}
顺便说一下,可以实现c++ 11版本的constexpr启用find:
生活#include <cstddef>
#include <cassert>
#if !defined(__clang__) && __GNUC__ < 5
// TODO: constexpr asserts does not work in gcc4, but we may use
// "thow" workaround from
// http://ericniebler.com/2014/09/27/assert-and-constexpr-in-cxx11/
# define ce_assert(x) ((void)0)
#else
# define ce_assert(x) assert(x)
#endif
namespace my {
template <class It, class T>
inline constexpr It
find (It begin, It end, T const& value) noexcept
{
return ! (begin != end && *begin != value)
? begin
: find (begin+1, end, value);
}
template<class Array>
class array_iterator
{
public:
using value_type = typename Array::value_type;
constexpr array_iterator(const Array& array, size_t size = 0u) noexcept
: array_ (&array)
, pos_ (size)
{}
constexpr const value_type operator* () const noexcept
{
return ce_assert (pos_ < Array::size), (*array_) [pos_];
}
#if __cplusplus >= 201402L // C++14
constexpr
#endif
array_iterator& operator ++() noexcept
{
return ce_assert (pos_ < Array::size), ++pos_, *this;
}
constexpr array_iterator operator+ (size_t n) const noexcept
{
return ce_assert (pos_+n <= Array::size), array_iterator (*array_, pos_+n);
}
friend constexpr bool
operator != (const array_iterator& i1, const array_iterator& i2) noexcept
{
return i1.array_ != i2.array_ || i1.pos_ != i2.pos_;
}
friend constexpr size_t
operator- (array_iterator const& i1, array_iterator const& i2) noexcept
{
return ce_assert (i1.array_ == i2.array_), i1.pos_ - i2.pos_;
}
private:
const Array* array_;
size_t pos_;
};
template<typename T, size_t N>
class array
{
public:
using value_type = T;
using const_iterator = const array_iterator<array>;
constexpr value_type const&
operator[] (size_t idx) const noexcept
{ return array_[idx]; }
constexpr const_iterator begin() const noexcept
{ return const_iterator(*this); }
constexpr const_iterator end() const noexcept
{ return const_iterator(*this, N); }
T array_[N];
static constexpr size_t size = N;
};
}
int main()
{
static constexpr my::array<int, 3> array{{0,2,3}};
static_assert (
find (array.begin(), array.end(), 2) - array.begin () == 1,
"error");
}
您可能也有兴趣检查Sprout库,它包含许多constexpr数据结构和算法。
相关文章:
- 查找表究竟是如何工作的,以及如何实现它们
- 为什么我的 Rcpp 实现查找唯一项的数量比基本 R 慢?
- pacman 实现 BFS 来查找 pacman 路径
- 如何实现 std::map::查找包含两个结构'Pos'结构的比较逻辑,每个结构包含 x 和 y 坐标
- 查找矩阵实现的 [] 运算符中的设计缺陷
- 在哪里查找 GCC 实现定义行为的实现?
- 在我的图实现中查找边的数量并执行拓扑排序
- 在使用无序多映射实现的有向图中查找循环
- 如何在将多维 int 数组映射到 C++ 中的字符串时实现在地图上查找或计数
- 实现用于查找路径的递归函数时出现问题
- 分段错误(核心转储)实现联合查找C++
- C++中无向图算法中查找周期的实现.
- 查找使用AgentX实现SNMP表的示例代码
- matlab在opencv中查找函数的实现
- 如何查找编译器实现细节
- 如何在c++中使用映射实现模板的返回类型查找
- 查找最近的点对-如何在递归侧对函数调用中实现拆分对
- Constexpr查找实现
- 为什么不为' at '和' operator[] '实现异构比较查找
- 给定一个按行排序的整数矩阵结构,如何实现二分查找?