Подтвердить что ты не робот

Возможно ли законная перегрузка строкового литерала и const char *?

Возможно ли в С++ 11 перегрузить const char* и строковые литералы (const char[])? Идея состоит в том, чтобы не называть strlen, чтобы найти длину строки, когда эта длина уже известна.

Этот фрагмент разбивается на g++ 4.8 и Clang++ 3.2:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

template<typename T, int N>
void length(const T(&data)[N]) {
  printf("%u[]\n", N - 1);
}

template<typename T>
void length(const T* data) {
  printf("*%u\n", (unsigned)strlen(data));
}

int main() {
  length("hello");
  const char* p = "hello";
  length(p);
  return 0;
}

Ошибка (Clang):

test2.cpp:16:3: error: call to 'length' is ambiguous
  length("hello");
  ^~~~~~
test2.cpp:6:6: note: candidate function [with T = char, N = 6]
void length(const T(&data)[N]) {
     ^
test2.cpp:11:6: note: candidate function [with T = char]
void length(const T* data) {
     ^
1 error generated.

Немного взломано, и это работает:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

template<typename T, int N>
void length(const T(&data)[N]) {
  printf("%u[]\n", N - 1);
}

template<typename T>
void length(T&& data) {
  printf("*%u\n", (unsigned)strlen(data));
}

const char *foo() {
   return "bar";
}

int main() {
  length("hello");
  const char* p = "hello";
  length(p);
  length(foo());
  return 0;
}

Является ли это допустимым С++ 11? Строковый литерал перегружается на T&&, когда специализация массива удаляется. Что вызывает эту неоднозначность для решения, но не в первом фрагменте кода?

4b9b3361

Ответ 1

В первом случае во время разрешения перегрузки у вас есть идеальное соответствие, не требующее преобразования против массива в преобразование указателя (которое находится в категории "преобразование lvalue", а также lvalue to rvalue и функция преобразования указателя). Разница, которая возникает только при преобразовании lvalue, недостаточна для разрешения перегрузки, чтобы выбрать победителя.

Во втором случае при разрешении перегрузки обе функции имеют один и тот же тип параметра. Затем частичный порядок в последнем случае обнаруживает, что второй шаблон принимает все аргументы, которые вы когда-либо проходили, но первый шаблон принимает только массивы. Поэтому первый шаблон во втором случае более специализирован и взят.


Что касается вашего другого вопроса - нет, перегрузка специально для строковых литералов невозможна. Вы всегда будете собирать массивы одинакового размера вместе с ними.