Это сбивает с толку формулировку, которая была скопирована непосредственно из стандарта :
Если [набор перегрузки] содержит шаблон буквального оператора с параметром шаблона без типа для который 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 как часть массива.