2017-01-03 15 views
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.Почему clang принимает строковый литерал как указатель, а не массив?

Выход:

Arg является указателем

Однако, согласно cppreference.com,

Типом без префикса строки буквального является Const символ [] ,

Почему разрешение перегрузки не ведет себя так, как ожидалось?

+2

Эквивалентный пример, но абстрагируясь от шаблона: http://melpon.org/wandbox/permlink/0nGenu5Ysj40wS8u –

+0

[Близко связанный] (https://stackoverflow.com/questions/16708307/is-it-possible-to -legally-overload-a-string-literal-and-const-char), возможный обман. Как вы думаете? –

ответ

8

Он ведет себя, как и ожидалось, вам просто нужно настроить ваши ожидания ;-)

const char[1] и const char (&)[1] различные типы.

Преобразования в const char* (преобразование матрицы в указатель) и const (&char)[1] (преобразование идентичности) считаются точными совпадениями, но не шаблон является лучшим совпадением, чем шаблон.

Если вы пишете перегрузку нешаблонном размера конкретного,

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

вы получите сообщение об ошибке, что вызов функции неоднозначен.

+2

Слишком медленно. : (Для справки, соответствующая стандартная информация приведена в таблице 12 в N4141 –

1

@ ответ molbdnilo правильный. Чтобы добавить одну деталь: ваша интуиция была бы правильной, и компилятор предпочел бы избежать преобразования матрицы в указатель, вызвав шаблон. Но преобразования lvalue (lvalue-to-rvalue, array-to-pointer и function-to-pointer) специально игнорируются при ранжировании перегрузки, согласно [over.ics.rank] §13.3.3.2/3.2.1.

Существует workaround: добавьте подделку volatile, чтобы восстановить баланс перегрузки. Перед использованием параметра обязательно удалите его const_cast.