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

Является специализацией std:: to_string для пользовательских типов, разрешенных стандартом С++?

В С++ 11 и более поздних версиях разрешено специализировать std::to_string в пространстве имен std для пользовательских типов?

namespace std {
string to_string(::MyClass const & c) { return c.toString(); }
}

Пример использования:

int main() {
    MyClass c;
    std::cout << std::to_string(c) << std::endl;
}
4b9b3361

Ответ 1

В С++ 11 и более поздних версиях разрешено специализировать std:: to_string в пространстве имен std для пользовательских типов?

Нет. Прежде всего, это не функция шаблона, поэтому вы не можете специализировать его вообще.

Если вы спрашиваете о добавлении собственных функций перегрузки, ответ остается неизменным.

Фрагмент документации из Расширение пространства имен std:

Поведение undefined добавляет объявления или определения в пространство имен std или любое пространство имен, вложенное в std, с несколькими исключениями, отмеченными ниже

Разрешено добавлять специализированные шаблоны для любого стандартного шаблона библиотеки в пространство имен std, только если объявление зависит от пользовательского типа, а специализация удовлетворяет всем требованиям для исходного шаблона, за исключением случаев, когда такие специализации запрещены.


На практике все, вероятно, будет работать нормально, но, строго говоря, стандарт говорит, что нет гарантии того, что произойдет.


Изменить: у меня нет доступа к официальному стандарту, так что из бесплатной рабочей страницы (N4296):

17.6.4.2 Использование пространства имен

17.6.4.2.1 Пространство имен std

  • Поведение программы на С++ undefined, если оно добавляет объявления или определения к пространству имен std или к пространство имен в пространстве имен std, если не указано иное. Программа может добавить специализацию шаблона для любого стандартного шаблона библиотеки для пространства имен std, только если объявление зависит от пользовательского типа и специализация соответствует стандартным требованиям библиотеки для исходного шаблона и не является явно запрещено. 181
  • Поведение программы на С++ undefined, если оно объявляет

    2.1 - явная специализация любой функции-члена стандартного шаблона библиотечного класса или

    2.2 - явная специализация любого шаблона функции-члена стандартного класса библиотеки или шаблона класса, или

    2.3 - явная или частичная специализация любого шаблона класса элемента стандартного класса или класса библиотеки шаблон.

    Программа может явно создавать шаблон, определенный в стандартной библиотеке, только если декларация зависит от имени определяемого пользователем типа и экземпляра соответствует стандартным требованиям библиотеки для исходного шаблона.

  • Единица перевода не должна объявлять пространство имен std внутренним пространством имен (7.3.1).

Ответ 2

Если я не ошибаюсь, вы можете просто перегрузить to_string для родового типа:

template<typename T> to_string(const T& _x) {
    return _x.toString();
}

и это позволяет использовать ADL (зависимый от аргументов поиск) вашей программой, чтобы правильно выбрать соответствующий метод to_string, основанный на переданном типе.

Ответ 3

Лучше всего было бы создать свою собственную функцию, которая может использовать std::to_string, если это возможно, а также метод .toString() всякий раз, когда он доступен для переданного аргумента:

#include <type_traits>
#include <iostream>
#include <string>

struct MyClass {
   std::string toString() const { return "MyClass"; }
};

template<class T>
typename std::enable_if<std::is_same<decltype(std::declval<const T&>().toString()), std::string>::value, std::string>::type my_to_string(const T &t) {
    return t.toString();
}

template<class T>
typename std::enable_if<std::is_same<decltype(std::to_string(std::declval<T&>())), std::string>::value, std::string>::type my_to_string(const T &t) {
    return std::to_string(t);
}

int main() {
   std::cout << my_to_string(MyClass()) << std::endl; // will invoke .toString
   std::cout << my_to_string(1) << std::endl; //will invoke std::to_string
}