在C++中,constexpr成员函数与std::vector数据成员。

22
我正在尝试在一个C++类中实现一个constexpr成员函数,该函数返回一个模板参数。代码应该与c++11兼容。然而,当模板类还包含STL容器作为数据成员时(这些容器不受constexpr成员函数的影响),我遇到了编译问题。
以下是一个最简示例代码:
#include <vector>
#include <iostream>
#include <array>

template<size_t n>
struct A 
{
    constexpr size_t dimensions() const
    {
        return n;
    }
private:
    std::vector<double> a;
};

 
int main(int argc,char ** argv)
{
    auto a=A<3>();
    std::array<double,a.dimensions()> arr;
}

使用以下命令,代码编译正确:

g++ -std=c++14 -O3 quickTest.cpp -o test -Wall

clang++ -std=c++11 -O3 quickTest.cpp -o test -Wall

但是,当我使用以下命令时出错:

g++ -std=c++11 -O3 quickTest.cpp -o test -Wall

错误信息如下:

quickTest.cpp:22:33: error: call to non-‘constexpr’ function ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’
   std::array<double,a.dimensions()> arr;
                     ~~~~~~~~~~~~^~
quickTest.cpp:10:20: note: ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’ is not usable as a ‘constexpr’ function because:
   constexpr size_t dimensions() const
                    ^~~~~~~~~~
quickTest.cpp:22:33: error: call to non-‘constexpr’ function ‘size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]’
   std::array<double,a.dimensions()> arr;
                     ~~~~~~~~~~~~^~
quickTest.cpp:22:33: note: in template argument for type ‘long unsigned int’

为什么使用gcc -std=c++11编译时代码无法通过,但使用clang++ -std=c++11可以通过呢? 如何使这段代码片段在不支持c++14/17,只支持c++11的旧版本gcc上工作?
我正在使用gcc 8.1.1和clang 6.0.1。

2
C++14 放宽constexpr限制,所以这是可以的。问题是谁是对的,gcc还是clang?在我看来是gcc。 - Marek R
1
如果你启用了更多的警告,编译器会告诉你问题所在:https://godbolt.org/z/hRMsN0 警告:'constexpr'非静态成员函数'size_t A<n>::dimensions() const [with long unsigned int n = 3; size_t = long unsigned int]'的封闭类不是一个字面类型[-Wpedantic]注意:'A<3>'不是字面类型,因为:'A<3>'具有非平凡析构函数-> 这不是关于std::vector,而只是关于非平凡析构函数。 - Max Langhof
1
解决方案很简单:将dimensions变为static函数(并删除const)。https://godbolt.org/z/y_YuMU - Max Langhof
1个回答

20

C++11规定[dcl.constexpr]/8

...该函数所在的类必须是字面类型 ([basic.types])。

struct A不是一个字面类型,因为它有一个vector,因此它的非静态成员函数不能是constexpr

因此,在C++11模式下,GCC拒绝编译这段代码是正确的。

C++14删除了这个限制。

C++11的解决方案是将dimensions()声明为static

  static constexpr size_t dimensions()
  {
    return n;
  }

实时演示


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接