SFINAE Для обнаружения существования функции, не являющейся членом

Кто-нибудь знает метод специализации шаблона в зависимости от того, определен ли метод, не являющийся членом? Я знаю, что существует множество способов специализации, если функция-член существует, но я никогда не видел примера, не являющегося членом. Конкретная проблема заключается в том, чтобы специализировать оператора ‹< для shared_ptr, чтобы он применил оператор ‹<, если оператор ‹* определен для T, и распечатал просто местоположение указателя в противном случае. Было бы здорово, если бы все классы определили оператор ‹< как член, но, к сожалению, многие используют бесплатные функции. Я представляю себе что-то вроде следующего:

template <typename T>
typename enable_if< ??? ,std::ostream &>::type operator<<( std::ostream & os, const shared_ptr<T> & ptr )
{
  if(ptr)
   return os << *ptr;
  else
   return os << "<NULL>";
}

template <typename T>
typename disable_if< ??? ,std::ostream &>::type operator<<( std::ostream & os, const shared_ptr<T> & ptr )
{
  if(ptr)
   return os << static_cast<intptr_t>( ptr.get() );
  else
   return os << "<NULL>";
}

Изменить: для потомков это было рабочее решение. Обратите внимание, что boost :: shared_ptr уже имеет оператор по умолчанию ‹<, который выводит адрес, поэтому disable_if не требуется. Поскольку оператор ‹< возвращает ссылку, это работает. Я подозреваю, что в общем случае это должно быть адаптировано для отражения типа возвращаемого значения рассматриваемой функции.

template <typename T>
typename boost::enable_if_c< boost::is_reference<decltype(*static_cast<std::ostream *>(0) << *static_cast<T *>(0) )>::value, std::ostream &>::type operator<<( std::ostream & os, const boost::shared_ptr<T> & ptr )
{
  if(ptr)
   return os << *ptr;
  else
   return os << "<NULL>";
}

person tgoodhart    schedule 30.07.2010    source источник
comment
Это решение может быть полезно для ты. Другой подход к проблеме, но тот же результат. Если оператор не определен, он переходит к общей функции вывода, где вы можете делать все, что захотите. Не публиковать в качестве ответа, поскольку он не отвечает на вопрос заголовка, но я бы рекомендовал этот.   -  person GManNickG    schedule 31.07.2010
comment
Вы редко встретите классы, реализующие операторы вставки и извлечения потока в качестве функций-членов, поскольку именно stream должен быть левым операндом, а не классом.   -  person Rob Kennedy    schedule 31.07.2010
comment
Хороший звонок, Роб. Я не думал об этом.   -  person tgoodhart    schedule 31.07.2010
comment
Сразу скажу, я не думаю, что вам понадобится что-то из enable_if. Я думаю, что это будет работать только с decltype.   -  person Puppy    schedule 31.07.2010
comment
DeadMG, в этом случае вы, безусловно, правы, но я думаю, что это удачное следствие функции, которую мы хотим условно создать (оператор ‹< для shared_ptr ‹T›), и функции, существование которой мы запрашиваем (оператор ‹< для T) с таким же возвращаемым значением. В общем случае я не уверен, что вы можете сделать это без enable_if.   -  person tgoodhart    schedule 02.08.2010


Ответы (1)


Если вы используете C ++ 0x, вы можете просто использовать decltype.

template<typename Char, typename CharTraits, typename T>
        decltype(
            *(std::basic_ostream<Char, CharTraits>*)(nullptr) << *(T*)(nullptr)
        )

Это обязательно вызовет ошибку замены, если невозможно вывести T. Возможно, вы могли бы сделать что-то подобное в C ++ 03, но я не уверен, как это сделать.

Изменить: только что понял, что выражение decltype на самом деле не дает истинного или ложного значения и не компилируется. Но вы понимаете. Попробуй это.

person Puppy    schedule 30.07.2010
comment
Блестяще! Это сработало. Для потомков я включил свой полный код выше. - person tgoodhart; 31.07.2010
comment
Это вообще не дает общего решения. - person plasmacel; 04.12.2016