简单的constexpr函数无法用GCC编译(clang没关系)

时间:2016-01-29 08:31:47

标签: c++ language-lawyer c++14 template-meta-programming constexpr

以下代码does not compile与GCC 5.2(C ++ 14)。它是does compile和clang 3.6(C ++ 14)。 (原始代码可以找到here

#include <cstddef>
#include <algorithm>
#include <type_traits>
#include <utility>

template <typename T>
class aggregate_wrapper;

template <typename T, std::size_t n>
class aggregate_wrapper<T[n]> {
public:
  using array = T[n];

  template <typename... Ts, typename = decltype(array{std::declval<Ts>()...})>
  aggregate_wrapper(Ts&&... xs)
      : arr_{std::forward<Ts>(xs)...} {
    // nop
  }

  aggregate_wrapper(const array& arr) {
    std::copy(arr, arr + n, arr_);
  }
  aggregate_wrapper(array&& arr) {
    std::move(arr, arr + n, arr_);
  }

  operator T* () {
    return arr_;
  }
  operator const T* () const {
    return arr_;
  }

  constexpr std::size_t size() const {
    return n;
  }

private:
  array arr_;
};

int main() {
  aggregate_wrapper<int[3]> arr;
  static_assert(arr.size() == 3, "");
}

产生的错误消息是

main.cpp: In function 'int main()':
main.cpp:44:3: error: non-constant condition for static assertion
   static_assert(arr.size() == 3, "");
   ^
main.cpp:44:25: error: call to non-constexpr function 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]'
   static_assert(arr.size() == 3, "");
                         ^
main.cpp:34:25: note: 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]' is not usable as a constexpr function because:
   constexpr std::size_t size() const {
                         ^
main.cpp:34:25: error: enclosing class of constexpr non-static member function 'constexpr std::size_t aggregate_wrapper<T [n]>::size() const [with T = int; long unsigned int n = 3ul; std::size_t = long unsigned int]' is not a literal type
main.cpp:10:7: note: 'aggregate_wrapper<int [3]>' is not literal because:
 class aggregate_wrapper<T[n]> {
       ^
main.cpp:10:7: note:   'aggregate_wrapper<int [3]>' is not an aggregate, does not have a trivial default constructor, and has no constexpr constructor that is not a copy or move constructor

有什么想法吗?代码应该按照标准编译吗?

3 个答案:

答案 0 :(得分:3)

或者您可以将现有的可变参数构造函数作为constexpr构造函数来执行默认构造:

template <typename... Ts, typename = decltype(array{std::declval<Ts>()...})>
constexpr                      // <---- ADD THIS
aggregate_wrapper(Ts&&... xs)
   : arr_{std::forward<Ts>(xs)...} {
   // nop
}

答案 1 :(得分:1)

为了让g ++编译它,你需要添加一个默认的构造函数:

aggregate_wrapper() = default;

请参阅:http://coliru.stacked-crooked.com/a/df1ac057960bebc7

我觉得引擎盖下的铿锵声加了它,但我不是百分百肯定......

答案 2 :(得分:1)

海湾合作委员会错了。它的诊断部分地说:

re.findall

......但没有这样的规则。有关适用于此处的约束列表,请参见[dcl.constexpr] / 3.

您可以通过添加虚拟main.cpp:34:25: note: '<...>' is not usable as a constexpr function because: main.cpp:34:25: error: enclosing class of constexpr non-static member function '<...>' is not a literal type 构造函数来解决伪GCC诊断问题(如果您不希望任何真正的构造函数为{{1},那么该构造函数可以是私有和/或删除}}或将constexpr设为constexpr