Использование SFINAE для проверки глобального оператора <

Я хочу иметь несколько перегруженных глобальных to_string () функций, которые принимают некоторый тип T и преобразовать его в строковое представление. В общем случае я хочу написать:

template inline
typename enable_if::value
                && has_insertion_operator::value,
                   void>::type
to_string( T const &t, OutputStringType *out ) {
  std::ostringstream o;
  o << t;
  *out = o.str();
}

Моя реализация has_insertion_operator на данный момент такова:

struct sfinae_base {
  typedef char yes[1];
  typedef char no[2];
};

template
struct has_insertion_operator : sfinae_base {
  template static yes& test( U& );
  template static no& test(...);

  static std::ostream &s;
  static T const &t;

  static bool const value = sizeof( test( s << t ) ) == sizeof( yes ); // line 48
};

(Это заимствовано из this и это .) Кажется, это работает. Но теперь я хочу иметь перегруженную версию to_string для типов, у которых не есть operator , но действительно имеют свои собственные to_string () member , то есть:

template inline
typename enable_if::value
                && has_to_string::value,
                   void>::type
to_string( T const &t, OutputStringType *out ) {
  *out = t.to_string();
}

Реализация has_to_string :

#define DECL_HAS_MEM_FN(FN_NAME)                                      \
  template                                     \
  struct has_##FN_NAME : sfinae_base {                                \
    template struct type_check; \
    template static yes& test(type_check*);   \
    template static no& test(...);                           \
    static bool const value = sizeof( test(0) ) == sizeof( yes );  \
  }

DECL_HAS_MEM_FN( to_string );

(Эта часть, кажется, работает нормально. Она адаптирована из this .) Однако, когда у меня:

struct S {
  string to_string() const {
    return "42";
  }
};

int main() {
  string buf;
  S s;
  to_string( s, &buf ); // line 104
}

, я получаю:

foo.cpp: In instantiation of ‘const bool has_insertion_operator::value’:
foo.cpp:104:   instantiated from here
foo.cpp:48: error: no match for ‘operator<<’ in ‘has_insertion_operator::s << has_insertion_operator::t’

Похоже, что SFINAE не происходит. Как мне правильно написать has_insertion_operator , чтобы он определял, доступен ли глобальный оператор ?

FYI: Я использую g ++ 4.2.1 (тот, который поставляется как часть Xcode в Mac OS X). Также хотелось бы, чтобы код был только стандартным C ++ 03 без сторонних библиотек, например Boost.

Спасибо!

11
задан Community 23 May 2017 в 12:25
поделиться