C++:我可以将赋值运算符设为"explicit"吗?
C++: Can I make an assignment operator "explicit"
我的任务是迁移C++类库中的错误处理概念。之前简单返回bool(成功/失败)的方法应进行修改,以返回Result
对象,该对象传达机器可读的错误代码和人类可读的解释(以及其他一些在此无关紧要的内容)。
遍历数千行代码很容易出错,因此我试图从编译器那里获得对这项任务的最佳支持。
在其他成员方法中,我的result类有一个构造函数,它从代码和代码的赋值运算符中构造结果:
class Result
{
public:
typedef unsigned long ResultCode;
explicit Result(ResultCode code); // (1)
Result& operator=(ResultCode code); // (2)
};
备注:我通常会为ResultCode
使用枚举类,这将解决我的问题,但这不是一个选项。这是因为主要的设计目标是在不同的库中使用Result
,每个库都应该定义自己的一组结果代码,而不需要一个大的头文件来定义所有库的所有可能的结果代码。事实上,每个类都应该能够定义本地结果代码,以便可以从类头中获得可能的结果代码列表。因此,代码不能在Result
中枚举,它们必须由使用Result
类的类定义。
避免上的隐式转换
return true;
在客户端代码中的语句中,构造函数已被声明为显式的。但在嵌套方法调用中,会出现另一个问题。比方说,我有一个方法
bool doSomething()
{
return true;
}
我在一个返回Result
对象的函数中使用它。我想转发嵌套调用的结果代码
Result doSomethingElse
{
Result result = doSomething();
return result;
}
对于Result
的赋值运算符的当前实现,这不会给我带来编译器错误——doSomething()的布尔返回值被隐式转换为无符号长。
正如我在C++文档中所读到的,只有构造函数和转换运算符可以声明为显式的。
我的问题
- 为什么不允许显式用于赋值运算符或其他方法?国际海事组织认为,允许任何方法都明确也是很有意义的
- 是否有其他解决方案可以防止赋值运算符的隐式类型转换
您的问题不在类Result
中:毕竟,您显式地创建了它的新实例;explicit
不能禁止它。
我认为你不能禁止bool -> long
的隐性促销。
一种方法是使ResultCode
不是为整数类型。然后,it可以有一个显式构造函数。类似的东西
class ResultCode
{
unsigned long m_code;
public:
explicit ResultCode(unsigned long code) : m_code(code) {}
operator unsigned long () { return m_code; }
};
将允许您在任何可以使用unsigned int
并将其创建为ResultCode res = 5
或return ResultCode(5)
的地方使用ResultCode
,但不使用任何已经不是ResultCode
的函数调用需要ResultCode
的函数(如Result
构造函数!),如果函数必须返回ReturnCode
,也不执行类似return 5
的操作。
否则,您可以使用模板重载来"捕获"任何不是unsigned int
的内容,并强制其为错误
typedef unsigned long ResultCode;
class Result
{
ResultCode m_par;
public:
template<typename T>
Result(T param) { static_assert(false); }
template<>
Result(ResultCode par): m_par(par) {}
};
int main()
{
ResultCode a = 5; //ok
//unsigned long a = 6; //also ok
//bool a = true; //error!
//int a = 7; //also error!!
Result b(a);
}
对于Result赋值运算符的当前实现,这不会给我带来编译器错误——doSomething()的布尔返回值被隐式转换为无符号长。
关于您发布的代码;它确实会导致错误error: no viable conversion from 'bool' to 'Result'
,请参阅此处。
需要一个显示您在代码中看到的行为的最小示例。实际代码中可能存在其他具有转换的构造函数或类型,这些构造函数或类型对您的代码具有实质性影响。
关于明确提出的问题。。。
为什么不允许显式用于赋值运算符或其他方法?
explicit
只允许在可以进行隐式转换的情况下使用,即编译器试图为您生成转换的情况(bool
有特殊情况)。这样的转换是构造函数和转换(或强制转换运算符)。
将构造函数或转换运算符标记为explicit
会阻止编译器进行转换,因此,如果您需要转换,则需要明确它——这是为什么要这样做的一般动机,它会使代码的操作更加明确。这是一种权衡,因此在这两种情况下都应该明智地使用。一般建议是在有疑问时支持explicit
。
例如;
struct Result {
Result(long src); // can be marked explicit
operator long() const; // can be marked explicit
};
是否有其他解决方案可以防止赋值运算符的隐式类型转换?
赋值运算符对Result& operator=(Result&);
具有特殊性。在赋值本身中,没有转换。为了防止为赋值隐式创建Result
,构造函数需要标记为explicit
。
为了防止从ResultCode
创建Result
,您可以不声明该方法,也可以将其标记为已删除;
Result& operator=(ResultCode code) = delete;
- 函数向量_指针有不同的原型,我可以构建一个吗
- 我可以使用 g++ 进行三种比较 (<=>) 吗?
- 我可以使用条件运算符初始化C风格的字符串文字吗
- 我可以信任表示整数的浮点或双精度来保持精度吗
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 为什么我可以通过引用修改常量返回
- 我可以在 C++ 中的函数体之外进行操作吗?
- 我可以重新分配/覆盖std::字符串吗
- C++-我可以创建另一个类的成员并在构造函数中使用它吗
- 我可以将调用类的"this"传递给 lambda 函数吗?
- 我可以检测和更改 gcc/g++ 中结构的当前数据对齐设置吗?
- 为什么我可以使用比分配的内存更多的内存
- 在一个读写器队列中,我可以用volatile替换原子吗
- 我可以把基础班提升为儿童班吗
- 我可以做些什么来消除或最小化这种将提供相同功能和行为的代码重复
- 我可以使用什么来停止循环而不是"返回 0"?
- 我可以使用反向迭代器作为ForwardIt吗
- 我可以创建一个包含两个变量的 for 循环,但时间复杂度仍然为 O(n) 吗?
- 我可以与 python 服务器而不是 c++ 客户端建立 tcp/ip 套接字吗?
- C++:我可以将赋值运算符设为"explicit"吗?