c++ - 强制类的 const 成员在编译时进行评估

标签 c++ c++11 constants sfml compile-time

我正在使用 SFML 创建贪吃蛇游戏,我有一个具体类 SnakeGame它包含我类的所有数据成员,例如窗口大小、游戏 map 的大小、蛇的颜色等。因此,我类的内部成员如下所示:

class SnakeGame
{
private:
    //....
    const sf::Vector2u windowSize{400, 336};
    const sf::Color snakeColor {0, 0, 0};
    //...etc...
public:
    SnakeGame() : 
        renderWindow {sf::VideoMode{windowSize.x, windowSize.y}, /*other arguments*/ },
        snake {snakeColor, /*other arguments*/} 
        /*etc*/ 
    {}

但是,这不起作用,我得到一个不可见的窗口,使我相信参数尚未构建。在阅读了另一篇 SO 帖子后,我读到了 const作为类成员的成员不会在编译时求值,而是在类被实例化时在运行时求值,否则它们的行为方式与 const 完全相同。变量。因此,变量 windowSizesnakeColor在我实例化 SnakeGame 时进行评估在main ,所以我不能在我的类的初始化列表中使用它们。为了尝试解决这个困境,我决定切换到 static constexpr变量,但不幸的是我意识到 sf::Vector<T>没有 constexpr构造函数,sf::Color 也没有.当然,我想我可以切换到整数类型,例如 static constexpr unsigned int对于窗口大小,但最终这会变得重复,尤其是对于颜色。所以我决定走另一条路。我所做的是创建另一个文件 GameData.hpp ,并在其中执行此操作:

namespace gd //For game data
{
    const sf::Vector2u windowSize{400, 336};
    const sf::Color snakeColor {0, 0, 0};
    //...etc...
}

但是,我不喜欢这个解决方案,因为即使现在在编译时评估此数据,如果它们包含适当的头文件,我的所有类也可以访问它,而不仅仅是 SnakeGame。 .这样一来,感觉我类的内部数据结构就暴露了。这引出了我的问题,即:有没有办法强制 const要在编译时以某种方式评估类的成员,以便这些变量可以在初始化列表中使用,并保证它们将被构造?

最佳答案

这里有几个选项,所有选项都需要权衡取舍。我按照我认为最好到最差的粗略顺序对它们进行了排名,但您的权衡可能会有所不同。

  • 重构您的代码,使颜色和窗口大小不再是全局常量。作为一名玩家,我想要一条绿蛇,而不是一条黑蛇,我想要一个两倍大的棋盘。这可能涉及将它们保留为成员变量,但这次不是常量,并且可能对它们重新排序,以便您可以在其他成员变量的初始化中使用它们。
  • 将编译器设置为 C++17 模式,并将 snakeColor 设置为 inline static const 变量。如果您想要一个仅包含 header 的库并且可以使用 C++17,那么这是最佳选择。
  • 使其成为const static 数据成员,并将const sf::Color SnakeGame::snakeColor {0, 0, 0} 添加到恰好一个。 cpp 文件。如果您不想要仅包含 header 的库,这是最佳选择。
  • 制作一个getColor static const sf::Color& getSnakeColor() 方法,里面有一个static常量它,并返回它。 static 关键字在函数内部的含义略有不同,您可以在那里做您想做的事。但是,这意味着您需要更改使用它的语法。
  • 按照您在回答中的建议使用命名空间。如果其他所有内容都在 namespace snake 中,那么您将这些变量放在 snake::details 中,然后按照惯例人们会知道他们不应该看那里。不过,与其他选项不同的是,这并不是强制执行的。
  • 使用 SFML 提交功能请求,以将 Vector2uColor 转换为文字类型,以便您可以使用 constexpr。显然,这需要更长的时间,而且不能保证一定有效。
  • 重新排序类以更有用的顺序排列成员,as suggested by VTT in the comments .这与第一个选项相同,我说过我最喜欢它,但是将它们作为常量,对于类的每个实例都具有相同的值。我将它放在列表底部的原因是,这意味着您的类的每个拷贝 都将带有颜色和窗口大小的拷贝,而您实际上只需要一个。

可能还有其他选项我忘记了。例如,有一种涉及辅助模板类的方法,您可以使用它来获取仅包含 header 的库,而无需 inline 成员变量支持,也无需切换到函数调用来访问数据,并且强制执行 private 说明符的地方。不过,我不太记得如何让它发挥作用,而且它比通常值得的要复杂得多。

关于c++ - 强制类的 const 成员在编译时进行评估,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45152302/

相关文章:

c++ - Boost::Thread/C++11 std::thread,想要在条件下唤醒工作线程

c++ - 一行替换多个字符串

c++ - 如何声明一个可以用作 "this"的 const 指针

c++ - 如何在不取消引用的情况下将指向不完整类型的指针转​​换为对不完整类型的引用

c++ - 在现代 C++ 中实现对象流容器的最佳实践

c++ - 插入 unordered_map<pair<int,int>, int> 抛出编译器错误

c++ - 在类中传递私有(private)变量 - 为什么不允许这样做?

groovy - 如何在groovy中访问全局变量

c++ - 如何在不重复代码的情况下转发到两个重载之一?

c++ - 函数模板内的 decltype 和范围解析运算符