带explicit构造函数的Foo类传基础类型调用append为何编译报错?
问题描述
我定义了如下Foo类:
class Foo { private: std::string m_data; public: Foo() = default; explicit Foo(double value); explicit Foo(float value); explicit Foo(int64_t value); explicit Foo(bool value); explicit Foo(const std::string& value); explicit Foo(const char* value); };
该类可通过整数、布尔值、浮点数等类型构造实例。另外有Bar类,其包含一个接受const Foo&引用的方法:
void append(const Foo& foo);
当我执行以下调用时,使用GCC 12.2.1编译器会报错:
调用1:
instanceOfBar.append(3.5);
报错信息:
无法将类型为'float'的右值绑定到类型为Foo的引用
调用2:
instanceOfBar.append(4);
报错信息:
无法将类型为'int'的右值绑定到类型为Foo的引用
调用3:
instanceOfBar.append(true);
报错信息:
无法将类型为'bool'的右值绑定到类型为Foo的引用
请问报错原因是什么?
报错原因
问题核心在于Foo类的所有构造函数都被标记为explicit。
C++中,explicit关键字的作用是禁止构造函数参与隐式类型转换。当你直接传入3.5、4、true这类值时,编译器原本会尝试将这些值隐式转换为Foo临时对象,再把这个临时对象绑定到const Foo&参数上。但explicit关键字直接阻断了这个隐式转换过程,编译器无法自动生成符合要求的Foo对象,因此抛出“无法绑定右值到Foo引用”的错误。
额外说一句:4是int类型,而Foo只提供了int64_t的构造函数,就算没有explicit,这里也需要先把int隐式转成int64_t,再构造Foo——explicit直接打断了整个转换链,自然也会报错。
解决方法
有两种常用的修复方式:
- 移除构造函数的
explicit关键字:如果不需要限制Foo的隐式转换,去掉explicit后,编译器就能自动完成类型转换,生成临时Foo对象绑定到参数上。 - 显式构造
Foo对象:手动触发构造过程,比如:
或者使用列表初始化语法:instanceOfBar.append(Foo(3.5)); instanceOfBar.append(Foo(static_cast<int64_t>(4))); // 显式将int转为int64_t instanceOfBar.append(Foo(true));instanceOfBar.append({3.5}); instanceOfBar.append({static_cast<int64_t>(4)}); instanceOfBar.append({true});
内容的提问来源于stack exchange,提问作者HeapOverflow
相关产品推荐
相关产品推荐

