Могу ли я создавать пользовательские литералы?

Предположим, что у меня есть класс:

template <typename T>
class Foo {
  const T* x_;
public:
  Foo(const T* str) : x_{str} {}
};

и я предоставляю некоторые пользовательские литералы, которые создают объект Foo:

Foo<char> operator"" _foo(const char* str, std::size_t) {
  return Foo<char>{str};
}

Foo<wchar_t> operator"" _foo(const wchar_t* str, std::size_t) {
  return Foo<wchar_t>{str};
}

// etc. for char16_t and char32_t.

Мой вопрос заключается в следующем: почему я не могу создать эти шаблоны и сохранить необходимость переписывать код?

template <typename T>
Foo<T> operator"" _foo(const T* str, std::size_t) {
  return Foo<T>{str};
}

gcc 5.4.0 (Ubuntu 5.4.0-6ubuntu1 ~ 16.04.4) и 7.0.0 (скомпилированный сам) отчет:

error: ‘Foo<T> operator""_foo(const T*, std::size_t)’ has invalid argument list
Foo<T> operator"" _foo(const T* str, std::size_t) {
                                                ^

Сообщение об ошибке кажется достаточно ясным, но я не вижу причины, по которой мне не должно быть позволено делать это в принципе; так, я делаю это неправильно, или это действительно не разрешено?

Ответы

Ответ 1

Рассмотрим this:

Если литеральный оператор является шаблоном, он должен иметь пустой список параметров и может иметь только один параметр шаблона, который должен быть пакетом параметров непигового шаблона с типом элемента char

Другими словами, объявление шаблона буквального оператора должно быть:

template <char...> double operator "" _x();

Это не ваше дело.


Я не юрист по языку, но я думаю, что раздел стандарта, который подходит для вашего дела, [over.literal] (ссылка на рабочий проект).

Отрывок из [over.literal]/2 следует:

Шаблон функции, объявленный с идентификатором literal-operator-id, является литеральным шаблоном оператора.

Ниже [over.literal]/5 цитируется:

Объявление шаблона шаблона литерала должно иметь пустое предложение-объявление-предложение, и его шаблон-параметр-список должен иметь один шаблон-параметр, который является непараметрическим пакетом шаблонов шаблонов ([temp.variadic]) с тип элемента char.

Мне кажется, что декларации, аналогичные той, что в вопросе, явно запрещены стандартом. Более того, шаблон функции, объявляющий литеральный оператор, должен строго придерживаться данного шаблона.


Я делаю это неправильно, или это действительно не разрешено?

Я бы сказал, что действительно не разрешено.

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

template<typename T>
Foo<T> create(const T *str) {
    // your logic...
    return Foo<T>{str};
}

Foo<char> operator"" _foo(const char *str, std::size_t) {
    return create(str);
}

Foo<wchar_t> operator"" _foo(const wchar_t *str, std::size_t) {
    return create(str);
}

Это вопрос дополнительного слоя косвенности и всего.
Очевидно, что это не стоит, если все ваши операторы являются функциями одной линии.