gpt4 book ai didi

c++ - 为什么我不能在类中另一个函数的声明中使用静态 constexpr 的结果?

转载 作者:塔克拉玛干 更新时间:2023-11-03 01:41:33 25 4
gpt4 key购买 nike

这是我的准系统代码:

#include <iostream>
#include <array>

class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };
static constexpr std::size_t NumValues() { return 3; }
static constexpr std::array<eValue, NumValues()> Values() { return {k_Red, k_Green, k_Blue}; }
};

int main() {
std::cout << "NumColors=" << cColor::NumValues() << '\n';
}

我正在尝试将 Values() 声明为静态 constexpr,我认为我应该能够使用 NumValues(),因为它也是一个静态 constexpr。然而,这个程序fails to compile并抛出此错误:

main.cpp:8:39: error: non-type template argument is not a constant expression
static constexpr std::array<eValue, NumValues()> Values() { return {k_Red, k_Green, k_Blue}; }
^~~~~~~~~~~
main.cpp:8:39: note: undefined function 'NumValues' cannot be used in a constant expression
main.cpp:7:32: note: declared here
static constexpr std::size_t NumValues() { return 3; }

但是,如果我使用静态 constexpr 成员变量它 works just fine .

#include <iostream>
#include <array>

class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };
static constexpr std::size_t NumValues {3};
static constexpr std::array<eValue, NumValues> Values() { return {k_Red, k_Green, k_Blue}; }
};

int main() {
std::cout << "NumColors=" << cColor::NumValues << '\n';
}

那么阻止代码编译的静态 constexpr 成员函数是什么?

最佳答案

这是因为它在类定义中。在类的完整定义之前,您不能在编译时使用类的静态函数。

如果不清楚原因,你的代码其实是这样的:

class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };
static constexpr std::size_t NumValues() { return 3; }
static constexpr std::array<cColor::eValue, cColor::NumValues()> Values() { return {k_Red, k_Green, k_Blue}; }
};

你看,当你说 std::array<cColor::eValue, cColor::NumValues()>作为返回类型,您使用的是 cColor::NumValues() ,它使用 cColor尚未定义(因为它在类定义中。

您有效地定义了 cColor 的一个组件就其本身而言。

通过将自引用组件移到类之外(其中之一或两者)解决了该问题:

#include <iostream>
#include <array>

static constexpr std::size_t NumValues() { return 3; }

class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };

static constexpr std::array<eValue, NumValues()> Values() { return {k_Red, k_Green, k_Blue}; }
};

int main() {
std::cout << "NumColors=" << NumValues() << '\n';
}

编辑:

为了进一步回答您的问题,即为什么特别使用 constexpr 函数会导致问题(与使用 constexpr 变量的修改后的问题相反),我将提供下一条信息:

你有没有注意到你不能在声明之前使用一个函数,但是你可以在它被声明之前使用一个成员函数(我的意思是在类定义中)。

那是因为 C++ 编译器在执行任何其他操作之前会忽略整个类,包括成员/静态变量和方法/静态方法。因此,方法/静态方法(我将统称为成员函数)必须在定义其任何实际实现之前具有格式正确的声明 - 这当然包括它们的返回类型。

因此,在编译时,当声明 Values() 时检查后,它知道返回类型取决于 NumValues() , 它知道 NumValues()返回 std::size_t , 但它还没有检查类中任何成员函数的实现。因此它(还)不知道 NumValues()将返回 3 .

因此,您也可以使用延迟返回类型推导来解决这个问题。问题的真正症结在于 Values()在检查其类的成员函数的实现之前,必须具有格式正确的返回类型。

这是另一个可能阐明问题细节的解决方案:

#include <iostream>
#include <array>

class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };
static constexpr std::size_t NumValues() { return 3; }
static constexpr auto Values() { return std::array<eValue, NumValues()>{k_Red, k_Green, k_Blue}; }
};

int main() {
std::cout << "NumColors=" << cColor::NumValues() << '\n';
}

你看,auto是签名的有效返回类型,实际返回类型是从方法实现中推导出来的,此时它知道 NumValues() 的实现。 .

这种奇怪的编译器解析顺序的原因是您不必按特定顺序安排方法来编译它们(在正常情况下 - 继续阅读)。这样,所有方法在任何实现之前都是已知的,这有点就像对类中的每个方法都有一个前向声明。

如果您想知道,是的,移动 NumValues() 的定义/声明在Values()之后将导致编译失败,因为自从 NumValues() 的实现以来我们的技巧不再有效在执行 Values() 后进行检查因此 Values()不知道NumValues()返回 3 :

class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };

// THIS ORDERING FAILS TO COMPILE
static constexpr auto Values() { return std::array<eValue, NumValues()>{k_Red, k_Green, k_Blue}; }
static constexpr std::size_t NumValues() { return 3; }
};

您的示例有效,因为必须同时定义和声明 constexpr 变量,因此 3 的值从那时起就知道了,从而使声明有效。但是,如果将静态 constexpr 成员变量的声明/定义移动到 Values() 之后您再次遇到编译错误,可以使用 auto 修复该错误我在上面演示了 hack。

class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };

// THIS ORDERING FAILS TO COMPILE
static constexpr std::array<eValue, NumValues> Values() { return {k_Red, k_Green, k_Blue}; }
static constexpr std::size_t NumValues = 3;
};
class cColor {
public:
enum eValue { k_Red, k_Green, k_Blue };

// AUTO TRICK MAKES THIS WORK
static constexpr auto Values() { return std::array<eValue, NumValues>{k_Red, k_Green, k_Blue}; }
static constexpr std::size_t NumValues = 3;
};

关于c++ - 为什么我不能在类中另一个函数的声明中使用静态 constexpr 的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56799393/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com