繁体   English   中英

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

[英]Why can't I use the result of a static constexpr in the declaration of another function in a class?

这是我的准系统代码:

#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。 但是,此程序无法编译并抛出此错误:

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成员变量,它可以正常工作

#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黑客修复该错误。

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;
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM