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

C++ Change function resolution precedence in constructor

本文关键字:优先级 函数 构造函数      更新时间:2023-10-16

考虑以下代码:

#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

像#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作为候选构造函数