2017-08-25 36 views
1

我试图实现一个constexpr栈只为了解constexpr。 我从下面的代码编译错误,我不明白:Gcc 7.2 C++ 17 constexpr

  1. 如果我理解正确constexpr并不意味着常量
  2. 它编译包含呼叫推
  3. 初始化列表constexpr构造
  4. 它编译执行弹出的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_type{0}; 
     } 

     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_type{0}; 
      top_item_ = size_type{0}; 
     } 

     constexpr array_stack() 
      : items_{size_type{0}}, top_item_{size_type{0}}, 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_type{0}; 
      rhs.top_item_ = size_type{0}; 
     } 

     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> dstack{0,1,2,3,4,5,6,7,8,9}; 
    constexpr ds::array_stack <int, 10> dstack2{dstack}; 
    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() 
         ^~~ 

回答

3
  1. 如果我理解正确constexpr并不意味着常量

编号声明的对象constexprare indeed const。这就是为什么dstack2.pop()不合格 - 非常无聊和C++ 03的原因,你在const对象上调用非const成员函数。

一旦你删除dstack2.pop()行,一切都编译。

  • 它编译,它包含呼叫推
  • 它编译执行一个弹出
  • 在两个拉姆达SPOP初始化列表constexpr构造在这些情况下,您可以修改对象。在第一种情况下,你仍然在构造函数中 - 所以修改没问题,在构造期间,对象绝不是const(否则你不能构造它)。在lambda情况下,参数不是const - 它只是auto

    +0

    谢谢你的解释,但我不unserstand 3点。这是它被修改,使得constexpr对象我不得到的东西是不同的。无论如何+1 @ – Genxers

    +3

    @Genxers,最后检查'dstack.size()'。你的lambda修改*拷贝*。 – rustyx

    +0

    @RustyX肯定是的,但是在编译时完成,就像你从static_assert中看到的那样。这是我没有得到的行为。 – Genxers

    1

    [expr.const]/2

    表达式e是一个核心常量表达式除非e的评价,如下所述的抽象机的规则,将评估下列表达式之一:

    • [。 ..]
    • 对象的修改,除非它应用于文字类型的非易失性左值,该左值引用了其生命周期始于e的评估内的非易失性对象;