【问题标题】:C++ Change function resolution precedence in constructorC ++在构造函数中更改函数解析优先级
【发布时间】:2015-10-07 15:55:23
【问题描述】:

考虑以下代码:

#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&lt;char*&gt;

但编译器也可以尝试将第二个参数转换为 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

【问题讨论】:

  • 谢谢,我看到了另一个答案,正如预期的 initializer_list 优先于常规签名,但是如何解决我的特定问题?
  • 我正在重新打开我自己的 close-as-duplicate。 “为什么”在Why is initializer_list constructor preferred here? 得到了完整的回答,但这个问题并没有解决如果有机会解决这个问题
  • 有趣的是,initializer_list 构造函数甚至不应该是可行的,因为将字符串文字绑定到 char* 已在 C++11 标准中删除。编译器的行为不合规。
  • 归结为,你将如何制作一个只接受 char* 作为参数的 initializer_list
  • @dyp Atm 它只是抛出一个警告,也许在 C++14 中它会被真正禁用。

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


【解决方案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 视为候选构造函数。

【讨论】:

  • 自 C++11 起不再存在转换。因此,initializer_list ctor 仅因不符合标准的扩展名而被调用,看起来无法停用该扩展名:(
  • 顺便说一句,您也可以简单地将字符串文字转发到char const[..]。该转换只允许用于字符串文字,并且应禁止用于其他数组。 Live demo
  • @dyp 谢谢。已更新。
  • 我刚刚意识到不允许声明将原始字符串作为数组参数的文字运算符(模板)。多么愚蠢 - 这意味着不能使用基于字符串长度的任何固定大小的数组存储,即使它在编译时已知 m(
  • 通过将"A"_strong 替换为+"A" 来增加怪异因素;) 糟糕,gcc 仍将其转换为char*,而 clang 不会。漂亮的角落案例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 2011-04-03
  • 2010-12-16
  • 2023-04-09
  • 1970-01-01
  • 2011-11-27
相关资源
最近更新 更多