Ответ 1
Нет необходимости в enable_if
, используйте выражение SFINAE для выбора правильной перегрузки, когда присутствует operator<<
.
namespace detail
{
template<typename T>
auto stringify(std::stringstream& ss, T const& t, bool)
-> decltype(ss << t, void(), std::string{})
{
ss << t;
return ss.str();
}
template<typename T>
auto stringify(std::stringstream&, T const&, int)
-> std::string
{
return "No overload of operator<<";
}
}
template <typename T>
std::string stringify(const T& t)
{
std::stringstream ss;
return detail::stringify(ss, t, true);
}
Шаблон функции stringify
просто делегирует один из шаблонов функций detail::stringify
. Затем первый выбирается, если выражение ss << t
хорошо сформировано. Неименованный параметр bool
используется для устранения различий между двумя реализациями detail::stringify
. Поскольку основная функция stringify
проходит true
как аргумент detail::stringify
, первая будет лучше соответствовать, когда присутствует перегрузка operator<<
. В противном случае будет выбран второй.
Это выражение decltype(ss << t, void(), std::string{})
в обратном типе возврата первого шаблона stringify
, вероятно, заслуживает более подробного объяснения. Здесь мы имеем одно выражение, состоящее из 3 подвыражений, разделенных оператором запятой.
Первый, ss << t
то, что определяет, проходит ли, что шаблон функции подстановки параметров шаблона и будет добавлен к набору разрешения перегрузки. Это произойдет, если выражение корректно сформировано, т.е. Если рассматриваемый тип перегружает operator<<
.
Средняя Подвыражение, void()
не что-либо делать, кроме того, чтобы некоторые определенные пользователем operator,
не выбран (потому что вы не можете перегрузить operator,
с void
типа параметра).
третий, и крайний правый, суб-выражение, std::string{}
это то, что определяет тип возвращаемого detail::stringify
функции.