Непонятное поведение оператора + при инициализации строки

На какое-то время забросил плюсы. А теперь решил попрактиковаться и "въехал в пень". Есть вот такой код

#include <iostream>
#include <string>

int main()
{
    char c = '\20';
    std::string s = "qreqwerqw" + c;

    std::cout << s << '\n';
    return 0;
}

И есть резутьтат/вывод, который я так и не понял, как получается
Выыод GCC:

basic_string: construction from null is not valid

Выыод Clang:

string: construction from null is not valid

https://godbolt.org/z/crxeT9czz

Clang выдаёт предупреждение

 <source>:7:33: warning: adding 'char' to a string does not append to
 the string [-Wstring-plus-int]
     7 |     std::string s = "qreqwerqw" + c;
       |                     ~~~~~~~~~~~~^~~ <source>:7:33: note: use array indexing to silence this warning
     7 |     std::string s = "qreqwerqw" + c;
       |                                 ^  
       |                     &           [  ]

и вроде как понятно, что я пытаюсь сложить "метры" с "килограммами", и что причина в магии адресной арифметики. Но я не совсем понимаю, как в итоге в конструктор строки попал какой-то адрес из тела программы.
Правильно ли я понимаю?: Произошло автоматическое приведение массива char[] к указателю char* на его начало и к этому адресу прибавилось число (потому что char - это тоже числовой тип). И в итоге получили новый адрес. А так как строковый литерал обязан иметь размещение своего адреса, то он был размещен в тексте программы. И этот новый адрес тоже оказался на какое-то место в тексте программы со смещением от константы литерала.

*Добавлено -----------
Но если это так, не понимаю, почему это в принципе работает на всех компиляторах? (MS VisualStudio выдёт такое же) Ведь здесь компилятору нужно не просто выполнить автоприведение, а выполнить автоприведение результата метода, для вызова которого нужно выполнить автоприведение. Я думал стандарт не разрешает таких цепочек.


Ответы (2 шт):

Автор решения: Serge3leo

Забавное сравнение компиляторов вышло.

...и вроде как понятно, что я пытаюсь сложить "метры" с "килограммами", и что причина в магии адресной арифметики.

Это не так, Вы складываете const char * с целочисленным типом char, результат имеет тип const char *. Всё строго по стандартам C/C++.

Для значений в диапазоне от '\00' до '\11' всё более менее. Правда, clang считает это плохим стилем, но это ж вкусовщина.

А начиная с '\12' - это UB (Undefined Behaviour), и программа начинает нести пургу, к примеру, для \13 clang даёт код выдающий "asic_string: construction from null is not valid", а для '\40' код gcc выдаёт "nstruction from null is not valid".

P.S.

(MS VisualStudio выдёт такое же)

Не знаю, не знаю, но если в Compiler Explorer выбрать "x64 msvc v19.latest", он выдаст "честные": "���8�" ?

→ Ссылка
Автор решения: Harry
std::string s = "qreqwerqw" + c;

К char* прибавляется char, приведенный к int для адресной арифметики. Результат показать не могу, потому что это указатель на что-то далеко за строкой (и автоматически приводит к UB). И этот результат используется для инициализации строки (передается в конструктор).

std::string s = std::string("qreqwerqw") + c;

К string прибавляется char, а этот оператор уже работает иначе, действительно "дописывая" символ к строке.

→ Ссылка