C ++在构造函数中更改函数解析优先级

时间:2015-07-17 20:22:20

标签: c++ c++11 constructor initializer-list

请考虑以下代码:

#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_constructibleclass 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

1 个答案:

答案 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视为候选构造函数。