Gcc 7.2 c ++ 17 constexpr

时间:2017-08-25 13:47:36

标签: c++ gcc compiler-errors c++17

我尝试实现constexpr堆栈只是为了理解constexpr。 我从以下代码中得到了一个我不理解的编译错误:

  1. 如果我正确理解constexpr并不意味着const
  2. 它编译init-list constexpr构造函数,其中包含对push
  3. 的调用
  4. 它编译执行pop
  5. 的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 ()
                            ^~~
    

2 个答案:

答案 0 :(得分:3)

  
      
  1. 如果我正确理解constexpr并不意味着const
  2.   

没有。对象声明为constexpr are indeed const。这就是为什么dstack2.pop()格式不正确的原因 - 您在const对象上调用非const成员函数的非常无聊和C ++ 03的原因。

删除dstack2.pop()行后,所有内容都会编译。

  
      
  1. 它编译init-list constexpr构造函数,其中包含对push
  2. 的调用   
  3. 它编译执行pop
  4. 的lambda spop   

在这两种情况下,您都可以修改对象。在第一种情况下,您仍然在构造函数中 - 因此修改很好,在构造期间对象永远不会const (否则您无法构造它)。在lambda案例中,论证不是const - 它只是auto

答案 1 :(得分:1)

[expr.const]/2

  

表达式e是核心常量表达式,除非根据抽象机器的规则评估e将评估以下表达式之一:

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