作者:贴进你的心聆听你的世界 | 2023-09-10 10:45
在我们的项目中,我们使用了很多"使用"来明确说明应该表示的变量.它主要用于std::string
像PortalId
或者这样的识别器CakeId
.现在我们目前可以做的是
using PortalId = std::string;
using CakeId = std::string;
PortalId portal_id("2");
CakeId cake_id("is a lie");
portal_id = cake_id; // OK
我们不喜欢.我们希望在编译期间进行类型检查,以防止我们混合苹果和橙子,同时保留原始对象中的大多数yum yum方法.
所以问题是 - 这可以在C++中完成,使得使用将接近以下内容,分配将失败,我们仍然可以在地图和其他东西中使用它吗?
SAFE_TYPEDEF(std::string, PortalId);
SAFE_TYPEDEF(std::string, CakeId);
int main()
{
PortalId portal_id("2");
CakeId cake_id("is a lie");
std::map p_to_cake; // OK
p_to_cake[cake_id] = portal_id; // OK
p_to_cake[portal_id] = cake_id; // COMPILER ERROR
portal_id = cake_id; // COMPILER ERROR
portal_id = "1.0"; // COMPILER ERROR
portal_id = PortalId("42"); // OK
return 0;
}
我们已经尝试了一些与模板结合使用的宏,但是没有得到我们所需要的.并补充 - 我们可以使用c ++ 14.
编辑:我们想出的代码是
#define SAFE_TYPEDEF(Base, name) \
class name : public Base { \
public: \
template \
explicit name (Args... args) : Base(args...) {} \
const Base& raw() const { return *this; } \
};
这是丑陋的,不起作用.并且它不起作用我的意思是编译器没问题portal_id = cake_id;
.
EDIT2:添加了explicit
关键字,我们的代码实际上可以很好地用于示例.不确定这是否是正确的方法,是否涵盖所有不幸的情况.
1> Richard Hodg..:
这是一个最小的完整解决方案,可以满足您的需求.
您可以添加更多运算符等,以使该类在您认为合适时更有用.
#include
#include
#include
这是一个更新版本,也处理哈希映射,流式传输到ostream等.
您会注意到我没有提供转换为的运算符string
.这是故意的.我要求此类的用户通过提供重载来明确表达将其用作字符串的意图to_string
.
#include
#include
#include
@Jendas ?? 它有10行完全类型安全,高效的代码,可以完全满足您的项目需求.它与我们在高度可扩展的生产服务器中使用的代码相同.但这当然取决于你:)
*并且*它避免使用宏!
2> kamikaze..:
到目前为止提供的解决方案似乎过于复杂,所以这是我的尝试:
#include
enum string_id {PORTAL, CAKE};
template class safe_str : public std::string {
public:
using std::string::string;
};
using PortalId = safe_str;
using CakeId = safe_str;