понимание добавления пользовательских строковых литералов для c ++ 20 - PullRequest
1 голос
/ 11 июля 2020

Я обнаружил в строковом литерале , заданном пользователем, следующее:

Для определяемых пользователем строковых литералов пусть str будет литералом без суффикса ud:

a) Если набор перегрузки включает шаблон оператора строкового литерала без -type параметр шаблона, для которого str является правильно сформированным аргументом шаблона, то определяемое пользователем буквальное выражение обрабатывается как вызов функции operator "" X<str>(),

Для меня это звучит немного загадочно. Может ли кто-нибудь привести пример того, как это можно использовать?

Следующее не сработало вообще, и я не могу понять, что может быть параметром шаблона без типа для MyType. Кажется, это не char * или const char *:

template < ??? >
struct MyType 
{
    const char* c;
    constexpr MyType( const char* in ): c{in}{}
};

template < MyType t > auto operator ""_y() { return t; }

int main()
{
    "Check it"_y;
}

1 Ответ

3 голосов
/ 12 июля 2020

Это сбивает с толку формулировку, которая была скопирована непосредственно из стандарта :

Если [набор перегрузки] содержит шаблон буквального оператора с параметром шаблона без типа для который str является правильно сформированным аргументом-шаблоном

Немного сбивает с толку вопрос, к чему конкретно относится «для чего str является правильно сформированным аргументом шаблона». Прямое чтение отрывка из стандарта предполагает, что «для чего» относится к «параметру шаблона, не являющемуся типом», поскольку это текст, непосредственно предшествующий словам «для чего». Однако, если вы посмотрите, как в стандарте говорится, что функция будет вызываться, вы увидите следующее:

operator "" X<str>()

str передается оператору, что подразумевает, что произойдет неявное преобразование между str и «параметром шаблона без типа». То есть str является допустимым «аргументом шаблона» перегруженной функции , а не параметром шаблона перегруженной функции. Таким образом, часть «для чего» должна относиться к «шаблону буквального оператора с параметром шаблона без типа», а не к «параметру шаблона без типа».

Сказанное , чтобы ваш код работал, вам нужно сделать больше, чем просто удалить аргумент шаблона из MyType.

Возможно, вы заметили некоторую странность в C ++, окружающем нетиповые параметры шаблона (NTTP) . Например, NTTP всегда могли указывать на вещи. Но вы никогда не сможете этого сделать:

template<const char *literal> void foo() {}
foo<"literal">();

Стандарт однозначно запрещает инициализацию указателя NTTP строковым литералом. И C ++ 20 это не меняет .

Следовательно, вы не можете взять указатель. Вы должны взять то, что на самом деле представляет собой литерал: массив. Но вы не можете заставить свой код работать, взяв const char (&in)[] в качестве параметра. Литерал не является массивом без размера (поскольку «массив без размера» не является реальным типом объекта). Этот параметр массива должен иметь размер , соответствующий литералу.

Это означает, что вы должны вывести размер из параметра шаблона размера.

Также , другие правила категорически запрещают вам когда-либо сохранять указатель на строковый литерал в NTTP (прямо или косвенно). Итак, если вам нужен тип, представляющий весь строковый литерал в NTTP, этот NTTP-тип должен содержать массив, размер которого соответствует этому размеру.

Итак, простейший функциональный строковый литерал NTTP , который вы можете построить, будет :

template<size_t N>
struct string_literal
{
    std::array<char, N> arr_;

    constexpr string_literal(const char(&in)[N]) : arr_{}   
    {
        std::copy(in, in + N, arr_.begin());
    }
};

И благодаря CTAD вы можете просто использовать template < string_literal t > auto operator ""_y() для определения своего UDL.

Обратите внимание, что это string_literal класс явно включает терминатор NUL как часть массива.

...