2017-08-25 38 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的評估內的非易失性對象;