【问题标题】:Simple constexpr function failed to compile with GCC (clang is OK)简单的 constexpr 函数无法使用 GCC 编译(clang 可以)
【发布时间】:2016-01-29 08:31:47
【问题描述】:

以下代码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

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

【问题讨论】:

  • 构造函数未标记为constexpr。既不是arr
  • @Jarod42 所以,基本上,clang 在这里不符合要求?
  • @Lingxi :代码肯定是格式错误的; constexpr 成员函数在非文字类型上是非法的。但是,这可能是不需要诊断的情况。
  • @ildjarn 该限制已被CWG1684删除

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


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    aggregate_wrapper() = default;
    

    请在http://coliru.stacked-crooked.com/a/df1ac057960bebc7查看实际操作

    我感觉引擎盖下的 clang 添加了它,但我不是 100% 确定 ...

    【讨论】:

    • size() 设为静态成员似乎是更好的解决方案。
    【解决方案3】:

    GCC 是错误的。它的诊断部分显示:

    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
    

    ...但是没有这样的规则。请参阅 [dcl.constexpr]/3 了解此处适用的约束列表。

    您可以通过添加一个虚拟的 constexpr 构造函数来解决虚假的 GCC 诊断问题(如果您不希望任何真正的构造函数成为 constexpr,则可以将该构造函数设为私有和/或删除)或通过将size 设为static

    【讨论】:

      猜你喜欢
      • 2021-11-28
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-02
      • 2018-12-06
      • 1970-01-01
      • 2022-10-18
      相关资源
      最近更新 更多