处理与封闭类具有相同类型的"constexpr"静态数据成员的限制



我想给Color类赋予constexpr功能,它看起来像这样:

// color.hpp
struct Color
{
Color(int r, int g, int b, int a);
static const Color Red;
// ...
};

// color.cpp
Color::Color(int r, int g, int b, int a) { /* ... */ }
const Color Color::Red(255, 0, 0, 255);
// ...

我的愿望是保持这个类的API不变,因此我想完全删除color.cpp并对头文件进行这些更改:

// color.hpp
struct Color
{
constexpr Color(int r, int g, int b, int a) { /* ... */ }
inline static constexpr Color Red{255, 0, 0, 255};
// ...
};

但是,上面的代码不能编译为C++中不允许使用与封闭类类型相同的constexpr静态数据成员。

当然,我可以将API更改为类似ColorConstants::Red的内容,并将Red对象移出类,但我不想破坏现有用户。

我唯一想到的解决方法是这样的:

// color.hpp
struct Color 
{
private:
struct ColorInit 
{
int r, g, b, a;
constexpr ColorInit(int r, int g, int b, int a) { /* ... */ }
constexpr inline operator Color() const { /* ... */ }
}
public:
constexpr Color(int r, int g, int b, int a) { /* ... */ }
inline static constexpr ColorInit Red{255, 0, 0, 255};
};

上面的解决方法允许大多数使用Color的现有代码在更改后仍然进行编译,但如果在需要隐式转换为Color的上下文中不使用Red,它显然会失败。

因此,我的问题是:是否可以绕过上述constexpr限制,将Red转换为常量表达式,同时仍然保留原始Color::Red语法并避免破坏现有代码

实现这一点的方法是让声明简单地为const,但有一个越界的定义,即inline constexpr,如下所示:

struct Color
{
constexpr Color(int r, int g, int b, int a) { /* ... */ }
static const Color Red;
// ...
};
inline constexpr Color Color::Red{255, 0, 0, 255};
// From this point on, Color::Red can be used in constant expressions.

我会:

  • 将常量分离到另一个类中
  • 将首选颜色表示形式放在命名空间中的类中
  • 创建一个新类,该类在另一个命名空间中重新创建旧的API,但使用using声明或类似声明

它比@Artyer的答案更多的是代码,但这将为您提供一种方法,让用户远离与语言不匹配的固定位置,同时保留旧代码。一旦迁移完成,您基本上只需删除代码即可进行清理。

类似于:

namespace v2 {
struct Color
{
constexpr Color(int r, int g, int b, int a) : r_(r), g_(g), b_(b), a_(a) {}
int r_, g_, b_, a_;
};
}
// todo: get rid of v1::Color use and make this a namespace 
struct ColorConstants {
static constexpr v2::Color Red{255, 0, 0, 255};
};
inline namespace v1 {
struct Color : v2::Color, ColorConstants {
using v2::Color::Color;
constexpr Color(v2::Color const& base) :v2::Color(base) {}
};
}

int
main()
{
constexpr Color light_color = Color::Red;
constexpr Color nice_color {255,165,0,255};
}

https://godbolt.org/z/ar497eYYM

最新更新