为什么clang将字符串字面值视为指针而不是数组?

7
#include <iostream>
using namespace std;

void f(const char* arg)
{
    cout << "arg is a pointer" << endl;
}

template<size_t N>
void f(const char (&arg)[N])
{
    cout << "arg is an array." << endl;
}

int main()
{
    f("");
}

我的编译器是clang 3.8。

输出结果为:

arg是一个指针

然而,根据cppreference.com

未加前缀的字符串文字的类型是const char[]。

为什么重载决议没有按预期行为?


2
等效的例子,但是抽象掉了模板:http://melpon.org/wandbox/permlink/0nGenu5Ysj40wS8u - Baum mit Augen
紧密相关,可能是重复问题。你认为呢? - Baum mit Augen
2个回答

8

它的行为符合预期,你只需要调整你的期望值 ;-)

const char[1]const char (&)[1] 是不同的类型。

将数组转换为指针(array-to-pointer) 和身份转换 (identity conversion) 都被认为是精确匹配,但非模板函数比模板函数更匹配。

如果你编写一个非模板的特定大小的重载函数,

void f(const char (&arg)[1])

如果函数调用不明确,您将会收到一个错误提示。


2
太慢了。 :( 相关的标准语在N4141的表格12中。 - Baum mit Augen

1

@molbdnilo的答案是正确的。添加一个细节:您的直觉是正确的,编译器会更喜欢调用模板以避免数组到指针的转换。但是,在重载排名中会明确忽略lvalue转换(lvalue-to-rvalue、array-to-pointer和function-to-pointer),根据[over.ics.rank] §13.3.3.2/3.2.1。

有一个解决方法:添加一个虚假的volatile来恢复重载优先级的平衡。只需在使用参数之前通过const_cast将其删除即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接