Gcc 7.2 c++17 constexpr
Posted
技术标签:
【中文标题】Gcc 7.2 c++17 constexpr【英文标题】: 【发布时间】:2017-08-25 13:47:36 【问题描述】:我尝试实现一个 constexpr 堆栈只是为了理解 constexpr。 我从以下代码中得到一个我不理解的编译错误:
-
如果我正确理解 constexpr 并不意味着 const
它编译包含 push 调用的 init-list constexpr 构造函数
它编译执行 pop 的 lambda spop
我错过了什么?
live example
g++ prog.cc -Wall -Wextra -I/opt/wandbox/boost-1.65.0/gcc-7.2.0/include -std=gnu++1z
#include <array>
#include <stdexcept>
#include <type_traits>
namespace ds
template <typename T, std::size_t N>
class array_stack final
public:
using value_type = T;
using reference = value_type&;
using const_reference = value_type const&;
using size_type = std::size_t;
constexpr bool empty () const
return items_ == size_type0;
constexpr bool full () const
return top_item_ == N;
constexpr size_type size () const
return items_;
constexpr reference top () &
if (empty())
throw std::logic_error"Attempting top() on empty stack";
return array_[top_item_ - 1];
constexpr const_reference top () const&
if (empty())
throw std::logic_error"Attempting top() on empty stack";
return array_[top_item_ - 1];
constexpr void push (value_type const& value)
if (full())
throw std::logic_error"Attempting push() on full stack";
array_[top_item_] = value;
top_item_++;
items_++;
constexpr void push (value_type&& value)
if (full())
throw std::logic_error"Attempting push() on full stack";
array_[top_item_] = std::move(value);
top_item_++;
items_++;
constexpr void pop ()
if (empty())
throw std::logic_error"Attempting pop() on empty stack";
top_item_--;
items_--;
constexpr void clear ()
items_ = size_type0;
top_item_ = size_type0;
constexpr array_stack ()
: items_size_type0, top_item_size_type0, array_
constexpr array_stack (std::initializer_list<value_type> values) : array_stack ()
for (auto const& v : values)
push(v);
constexpr array_stack (array_stack const& rhs) : array_stack ()
array_ = rhs.array_;
items_ = rhs.items_;
top_item_ = rhs.top_item_;
constexpr array_stack (array_stack&& rhs)
: items_ rhs.items_, top_item_ rhs.top_item_, array_ std::move(rhs.array_)
rhs.items_ = size_type0;
rhs.top_item_ = size_type0;
constexpr array_stack& operator= (array_stack rhs)
array_ = std::move(rhs.array_);
items_ = std::move(rhs.items_);
top_item_ = std::move(rhs.top_item_);
return *this;
~array_stack () = default;
void swap (array_stack& rhs) noexcept(std::is_nothrow_swappable_v<value_type>)
using std::swap;
swap(items_, rhs.items_);
swap(top_item_, rhs.top_item_);
swap(array_, rhs.array_);
private:
size_type items_;
size_type top_item_;
std::array<value_type, N> array_;
;
template <typename T, std::size_t N>
void swap (array_stack<T, N>& lhs, array_stack<T, N>& rhs) noexcept(noexcept(lhs.swap(rhs)))
lhs.swap(rhs);
constexpr bool f()
constexpr ds::array_stack <int, 10> dstack0,1,2,3,4,5,6,7,8,9;
constexpr ds::array_stack <int, 10> dstack2dstack;
constexpr auto spop =[](auto s) s.pop(); return s.size(); ;
static_assert(dstack.size() == 10);
static_assert(!dstack.empty());
static_assert(dstack.full());
static_assert(dstack.top() == 9);
static_assert(dstack2.size() == 10);
static_assert(spop(dstack) == 9);
dstack2.pop();
return true;
int main()
constexpr ds::array_stack <int, 10> cstack;
static_assert(cstack.size() == 0);
static_assert(cstack.empty());
static_assert(!cstack.full());
static_assert(f());
return 0;
我收到此错误(我明白它的含义,但为什么?)
prog.cc: In function 'constexpr bool f()':
prog.cc:147:15: error: passing 'const ds::array_stack<int, 10>' as 'this' argument discards qualifiers [-fpermissive]
dstack2.pop();
^
prog.cc:66:24: note: in call to 'constexpr void ds::array_stack<T, N>::pop() [with T = int; long unsigned int N = 10]'
constexpr void pop ()
^~~
【问题讨论】:
【参考方案1】:如果我正确理解 constexpr 并不意味着 const
没有。对象声明为constexpr
are indeed const
。这就是为什么 dstack2.pop()
格式不正确的原因 - 非常无聊和 C++03 原因,您在 const
对象上调用非 const
成员函数。
删除dstack2.pop()
行后,一切都会编译。
它编译包含 push 调用的 init-list constexpr 构造函数 它编译执行 pop 的 lambda spop
在这两种情况下,您都可以修改对象。在第一种情况下,您仍然在构造函数中 - 所以修改很好,对象永远不会是 const
during 构造(否则您无法构造它)。在 lambda 情况下,参数不是 const
- 它只是 auto
。
【讨论】:
感谢您的解释,但我不理解第 3 点。它是 constexpr 对象,它已被修改,所以我不明白有什么不同。无论如何+1 @Genxers,最后检查dstack.size()
。你的 lambda 修改了一个 copy.
@RustyX 是肯定的,但在编译时完成,正如您从 static_assert 中看到的那样。这是我不明白的行为吗?
我终于明白了... C++11,constexpr 成员函数是隐式 const。其次,它们有 void 返回类型,而 void 在 C++11 中不是文字类型。这两个限制都在 C++14 中从 S.Meyers 的书 Eff modern c++ 中解除【参考方案2】:
[expr.const]/2:
表达式 e 是核心常量表达式,除非根据抽象机的规则对 e 的求值将求值以下表达式之一:
[...] 对象的修改,除非将其应用于文字类型的非易失性左值,该左值引用一个非易失性对象,该对象的生命周期始于对 e 的评估;
【讨论】:
以上是关于Gcc 7.2 c++17 constexpr的主要内容,如果未能解决你的问题,请参考以下文章
如何在 CentOS 7.2 上使用 yum 安装 gcc 5.3?