【问题标题】:Is this overload resolution correct?这个重载解决方案正确吗?
【发布时间】:2014-07-09 19:37:54
【问题描述】:

发件人:Is it safe to overload char* and std::string?

#include <string>
#include <iostream>
void foo(std::string str) {
  std::cout << "std::string\n";
}

void foo(char* str) {
  std::cout << "char*\n";
}

int main(int argc, char *argv[]) {
  foo("Hello");
}

上面的代码在使用g++-4.9.0 -ansi -pedantic -std=c++11编译时打印“char*”。

感觉这样不对,因为字符串字面量的类型是"array of n const char",应该不可能初始化一个非const@ 987654327@ ,所以应该选择 std::string 重载。这里 gcc 违反标准了吗?

【问题讨论】:

  • 您还会收到一条警告:不推荐将字符串常量转换为 'char'(您需要 -Wall-Wwrite-strings 来实现)。不,这是不正确的。
  • @jrok 如果编译器实际上错误地编译了格式正确的程序,警告有什么用? ://
  • @jrok:在这种情况下不是,因为我们有一个具有完美定义行为的程序并且编译器编译它错误。这将其从“符合语言扩展”的划分转变为不符合标准的实现。
  • @Deduplicator 这不是真正的错误。那个人实际上是在抱怨编译器在使用带有 char * 的函数的字符串文字时冒昧地发出警告。

标签: c++ c++11 language-lawyer overload-resolution


【解决方案1】:

首先,字符串字面量的类型:它们都是其字符类型的常量数组。

2.14.5 字符串文字 [lex.string]

7 以 u8 开头的字符串文字,例如 u8"asdf",是 UTF-8 字符串文字,并使用 UTF-8 编码的给定字符进行初始化。
8 普通字符串文字和 UTF-8 字符串文字也称为窄字符串文字。窄字符串文字的类型为“n const char 数组”,其中 n 是字符串的大小,定义如下,并且具有静态存储持续时间 (3.7)。
9 以 u 开头的字符串文字,例如 u"asdf",是 char16_t 字符串文字。 char16_t 字符串文字的类型为“array of n const char16_t”,其中 n 是字符串的大小,定义如下;它具有静态存储持续时间并使用给定字符进行初始化。单个 c-char 可能会以代理对的形式产生多个 char16_t 字符。
10 以 U 开头的字符串文字,例如 U"asdf",是 char32_t 字符串文字。 char32_t 字符串文字的类型为“array of n const char32_t”,其中 n 是字符串的大小,定义如下;它具有静态存储持续时间,并使用给定的字符进行初始化。
11 以 L 开头的字符串文字,例如 L"asdf",是一个宽字符串文字。宽字符串文字的类型为“array of n const wchar_t”,其中 n 是字符串的大小,定义如下;它具有静态存储持续时间,并使用给定的字符进行初始化。

接下来,让我们看看我们只有标准的数组衰减,所以从T[#]T*

4.2 数组到指针的转换[conv.array]

1 “N T 的数组”或“T 的未知边界数组”类型的左值或右值可以转换为“指向 T 的指针”类型的纯右值。结果是指向数组第一个元素的指针。

最后,让我们看看任何符合标准的扩展都不能改变正确程序的含义:

1.4 实施合规性 [intro.compliance]

1 可诊断规则集由本国际标准中的所有句法和语义规则组成,但那些包含“不需要诊断”的明确表示法或被描述为导致“未定义行为”的规则除外。
2 尽管本国际标准仅规定了对 C++ 实现的要求,但如果将这些要求表述为对程序、程序部分或程序执行的要求,则通常更容易理解。此类要求的含义如下:

  • 如果程序不违反本国际标准中的规则,则符合要求的实现应在其资源限制内接受并正确执行2该程序。
  • 如果程序包含违反任何可诊断规则或出现在本标准中描述为“有条件支持”的构造,而实施不支持该构造,则符合要求的实施应发出至少一条诊断消息。
  • 如果程序违反了不需要诊断的规则,本国际 标准对该程序的实施没有任何要求。

所以,总而言之,这是一个编译器错误。

(在 C++11 (C++03) 之前,允许转换但已弃用,因此它是正确的。如果发生这种情况,则不需要进行诊断,而是作为实现质量问题提供的。)

这是一个 GCC 错误(尚未找到错误报告),也是一个 clang bug (found by T.C.)。

来自 clang 错误报告的测试用例,更短:

void f(char*);
int &f(...);
int &r = f("foo");

【讨论】:

    猜你喜欢
    • 2019-09-17
    • 1970-01-01
    • 1970-01-01
    • 2010-11-08
    • 2021-11-06
    • 1970-01-01
    • 2017-06-12
    • 2020-12-15
    • 1970-01-01
    相关资源
    最近更新 更多