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

G++ рассматривает возвращаемый строковый литерал как const char указатель not const char array

Я вижу некоторое нечетное поведение при возврате строкового литерала из функции, которая должна выполнять неявное преобразование с g++ (версия 4.7.3). Может кто-нибудь объяснить, почему следующий код:

#include <stdio.h>

class Test
{
public:
  template <unsigned int N>
  Test(const char (&foo)[N])
  {
    printf("Template const char array constructor\n");
  }

  Test(char* foo)
  {
    printf("char* constructor\n");
  }
};

Test fn()
{
  return "foo";
}

int main()
{
  Test t("bar");
  Test u = fn();

  return 0;
}

дает результат:

Template const char array constructor
char* constructor

на g++? Удивительно, что конструктор char * предпочтителен конструктор массива const char при генерации возвращаемого значения из fn(). По общему признанию, существует предупреждение: "устаревшее преобразование из строковой константы в" char * "

Еще более удивительно, если вы удалите конструктор char *, тогда код не скомпилируется с g++.

Он работает, как и ожидалось, с clang (используемый конструктор шаблонов одновременно), что заставляет меня думать, что это ошибка компилятора, но, возможно, это просто странный угол спецификации С++ - кто-нибудь может подтвердить?

4b9b3361

Ответ 1

Похоже, что это ошибка, влияющая на несколько версий gcc, которые сообщались снова и снова, совсем недавно около месяца назад, против самой последней версии, 4.8.2. См. http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24666

Ответ 2

Если вы хотите использовать многоразовый метод С++ 03 (то есть тот, в котором вам не нужно будет заботиться о том, какой тип возвращаемого значения, поскольку он является конструктивным из массива char), вам придется использовать некоторая оболочка массива char.

template <size_t N>
struct char_array_ref
{
    typedef const char (&ref_type)[N];
    ref_type ref;

    template <typename T>
    operator T() const
    {
        return T(ref);
    }
};

template <size_t N>
char_array_ref<N> stupid_gxx_use_array_reference(const char (&chars)[N])
{
    return char_array_ref<N> { chars };
}


Test fn()
{
  return stupid_gxx_use_array_reference("foo");
}

Должно быть легко regex распространять это и на вашу кодовую базу.

Очевидно, что в вашем коде вы можете изменить stupid_gxx_use_array_reference на нечто менее подробное.