explicit关键字在C++中意味着什么?
我有一个班级 private char str[256];
为此,我有一个显式的构造函数:
explicit myClass(const char *func)
{
strcpy(str,func);
}
Run Code Online (Sandbox Code Playgroud)
我称之为:
myClass obj("example");
Run Code Online (Sandbox Code Playgroud)
当我编译这个时,我得到以下警告:
不推荐将字符串常量转换为'char*'
为什么会这样?
使具有多个参数的构造函数explicit具有任何(有用)效果吗?
例:
class A {
public:
explicit A( int b, int c ); // does explicit have any (useful) effect?
};
Run Code Online (Sandbox Code Playgroud) 在C++标准§13.3.1.7[over.match.list]中,陈述如下:
在copy-list-initialization中,如果
explicit选择了构造函数,则初始化是错误的.
这就是为什么我们不能这样做的原因,例如:
struct foo {
// explicit because it can be called with one argument
explicit foo(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
f({ "answer", 42 });
Run Code Online (Sandbox Code Playgroud)
(注意,这里发生的不是转换,即使构造函数是"隐式的"也不会是一个.这是一个foo对象直接使用它的构造函数初始化.除此之外std::string,这里没有转换.)
这对我来说似乎完全没问题.隐式转换不会让我感到困惑.
如果{ "answer", 42 }可以初始化其他东西,编译器不会背叛我并做错事:
struct bar {
// explicit because it can be called with one argument
explicit bar(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
void f(bar x); …Run Code Online (Sandbox Code Playgroud) 我最近注意到C++ 0x中的一个类需要一个显式的默认构造函数.但是,我没有想出一个可以隐式调用默认构造函数的场景.这似乎是一个相当无意义的说明者.我想也许它会Class c;不赞成,Class c = Class();但似乎并非如此.
来自C++ 0x FCD的一些相关引用,因为我更容易导航[类似文本存在于C++ 03中,如果不在同一个地方]
12.3.1.3 [class.conv.ctor]
默认构造函数可以是显式构造函数; 这样的构造函数将用于执行默认初始化或值初始化(8.5).
它继续提供显式默认构造函数的示例,但它只是模仿我上面提供的示例.
8.5.6 [decl.init]
默认初始化T类型的对象意味着:
- 如果T是一个(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
8.5.7 [decl.init]
对值类型T的对象进行值初始化意味着:
- 如果T是具有用户提供的构造函数(12.1)的(可能是cv限定的)类类型(第9节),则调用T的默认构造函数(如果T没有可访问的默认构造函数,则初始化是错误的);
在这两种情况下,标准都要求调用默认构造函数.但是如果默认构造函数是非显式的,那就会发生这种情况.为了完整起见:
8.5.11 [decl.init]
如果没有为对象指定初始化程序,则默认初始化该对象;
据我所知,这只是从没有数据的转换.这没有意义.我能想到的最好的是以下内容:
void function(Class c);
int main() {
function(); //implicitly convert from no parameter to a single parameter
}
Run Code Online (Sandbox Code Playgroud)
但显然这不是C++处理默认参数的方式.还有什么会使explicit Class();行为与众不同Class();?
生成此问题的具体示例是std::function[20.8.14.2 func.wrap.func].它需要几个转换构造函数,其中没有一个被标记为显式,但默认构造函数是.
我理解具有一个(非默认)参数的构造函数就像隐式转换器,它从该参数类型转换为类类型.但是,explicit可用于限定任何构造函数,没有参数的构造函数(默认构造函数)或具有2个或更多(非默认)参数的构造函数.
为什么明确允许这些构造函数?有什么例子可以防止某种隐式转换吗?
explicit对于可以使用一个参数调用的所有 大多数构造函数,建议使用该关键字,但复制构造函数除外.
对于复制构造函数,它有一个用途(禁止通过函数调用,返回等隐式复制),但它不是通常想要的.
移动构造函数怎么样?是否有任何合理的用例使它们明确?这里的好习惯是什么?
有几次,在重构代码时,我忘记explicit在向以前无参数的构造函数添加参数时添加关键字,或者从先前的多参数构造函数中删除参数.为了防止这种情况,我养成了标记每个构造函数的习惯explicit,无论它有多少参数.(当然,除了那些我实际上想要隐式转换的构造函数.)
这有什么缺点吗?性能?编译时间?
在C++ 11中,我们可以使用"brace-or-equal-initializer"(标准中的单词)进行类内初始化,如下所示:
struct Foo
{
/*explicit*/ Foo(int) {}
};
struct Bar
{
Foo foo = { 42 };
};
Run Code Online (Sandbox Code Playgroud)
但如果我们不发表评论explicit,它就不再编译了.GCC 4.7和4.9说:
error: converting to ‘Foo’ from initializer list would use explicit constructor ‘Foo::Foo(int)’
Run Code Online (Sandbox Code Playgroud)
我发现这令人惊讶.C++ 11标准真的是这个代码无法编译的意图吗?
删除它=修复它:Foo foo { 42 };但我个人觉得更难以向那些已经习惯了这种形式的人解释=几十年,而且由于标准指的是"支撑或平等初始化器",因此很好的旧方式在这种情况下不起作用.
c++ explicit-constructor initializer-list in-class-initialization c++11
在C++ 17中,标准库中的空标记类型现在具有标记的默认构造函数explicit,并且也是= default.例如,std::piecewise_construct_t现在定义为
struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
Run Code Online (Sandbox Code Playgroud)
我的问题很简单,这是C++ 14改变的原因是什么?明确默认的显式默认构造函数(!)对空类的意义是什么?
(为了避免被标记为欺骗:2010年的这个问题询问了显式默认构造函数的用途,但那是在C++ 11之前和很久以前的事情,所以事情可能已经改变了.这个问题是最新的,但是答案似乎表明,无论是否存在默认构造函数,都会执行聚合初始化,因此我对最新标准中此更改的原因感到好奇.)