请考虑以下代码:
#include <cstdio>
#include <initializer_list>
using namespace std;
class A {
public:
A(const char*, void*) { printf("const char*, void*\n"); }; // #1
A(initializer_list<char*>) { printf("initializer_list<char*>\n"); }; // #2
};
void F(const A&) {};
int main(int, char**) {
F({ "A", new char[256]() });
};
我有一个函数F
,我可以使用is_constructible
到class A
的任何参数调用。
如果我运行程序,我会看到构造函数#2被调用,并且我收到第一个参数的警告:ISO C++11 does not allow conversion from string literal to 'char *const'
。 C ++会自动将此参数从字符串文字转换为char*
,以使调用与签名initializer_list<char*>
匹配。
但编译器也可以尝试将第二个参数转换为void*
,以便调用匹配签名const char*, void*
。
两个调用都采用“相同数量的步骤”从调用到“匹配签名”,但由于某种原因,编译器选择后者。
我想了解这个选择背后的基本原理,并且,如果第一个参数是字符串文字的话,是否有机会“提示”编译器使用构造函数#1。
总的来说,
我希望调用:F({ "A", new char[256]() })
来选择构造函数#1,
但是调用F({ (char*)"A", new char[256]() })
来选择构造函数#2。
编译器详细信息: Apple LLVM 6.0版(clang-600.0.57)(基于LLVM 3.5svn) 目标:x86_64-apple-darwin14.1.0 线程模型:posix
答案 0 :(得分:1)
像#2这样的初始化列表构造函数优先于其他构造函数。只要它是一个可行的构造函数,那么它们就会被考虑,尽管它可能是更可行的非初始化列表构造函数。字符串文字是N const char
的数组,从字符串文字转换为char*
作为遗留给C,但自C ++ 03以来已弃用。
由于无论如何都可以进行转换,因此仍然使用构造函数而不是#1。您可以通过将其转换为非文字(即通过从函数返回)来阻止此转换:
const char* operator"" _strong(const char* str, std::size_t) {
return str;
}
int main() {
F({ "A", new char[256]() }); // #1
F({ "A"_strong, new char[256]() }); // #2
}
现在转换为char*
将失败,重载解析会将#1视为候选构造函数。