11

いくつかの型を取り、それを文字列表現に変換するオーバーロードされたグローバルto_string()関数がいくつか必要です。T一般的なケースでは、次のように記述できるようにしたいと考えています。

template<typename T,class OutputStringType> inline
typename enable_if<!std::is_pointer<T>::value
                && has_insertion_operator<T>::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<typename T>
struct has_insertion_operator : sfinae_base {
  template<typename U> static yes& test( U& );
  template<typename U> static no& test(...);

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

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

(これ とこれから借りています。)それはうまくいくようです。しかし今、私はオーバーロードされたバージョンのto_stringforを持ちたいのですが、独自のメンバー関数を持っていません。つまり:operator<<to_string()

template<class T,class OutputStringType> inline
typename enable_if<!has_insertion_operator<T>::value
                && has_to_string<T,std::string (T::*)() const>::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<typename T,typename S>                                     \
  struct has_##FN_NAME : sfinae_base {                                \
    template<typename SignatureType,SignatureType> struct type_check; \
    template<class U> static yes& test(type_check<S,&U::FN_NAME>*);   \
    template<class U> static no& test(...);                           \
    static bool const value = sizeof( test<T>(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<S>::value’:
foo.cpp:104:   instantiated from here
foo.cpp:48: error: no match for ‘operator<<’ in ‘has_insertion_operator<S>::s << has_insertion_operator<S>::t’

SFINAEは起きていないようです。グローバルが利用可能かhas_insertion_operatorどうかを判断するように正しく記述するにはどうすればよいですか?operator<<

参考までに: g++ 4.2.1 (Mac OS X の Xcode の一部として出荷されるもの) を使用しています。また、Boost などのサードパーティ ライブラリを使用せずに、コードを標準の C++03 のみにしたいと考えています。

ありがとう!


ここに、開発者ツールにアクセスするためのショートカットがあります。

https://developer.chrome.com/devtools/docs/shortcuts

4

2 に答える 2

10

私は単にこの答えにもっと忠実であるべきでした. 実用的な実装は次のとおりです。

namespace has_insertion_operator_impl {
  typedef char no;
  typedef char yes[2];

  struct any_t {
    template<typename T> any_t( T const& );
  };

  no operator<<( std::ostream const&, any_t const& );

  yes& test( std::ostream& );
  no test( no );

  template<typename T>
  struct has_insertion_operator {
    static std::ostream &s;
    static T const &t;
    static bool const value = sizeof( test(s << t) ) == sizeof( yes );
  };
}

template<typename T>
struct has_insertion_operator :
  has_insertion_operator_impl::has_insertion_operator<T> {
};

実際には SFINAE に依存していないと思います。

于 2011-04-24T15:04:06.753 に答える
1

48 行目のイニシャライザはvalue、SFINAE が機能するコンテキストではありません。式を関数宣言に移動してみてください。

#include <iostream>

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

template<typename T>
struct has_insertion_operator : sfinae_base {

  // this may quietly fail:
  template<typename U> static yes& test(
      size_t (*n)[ sizeof( std::cout << * static_cast<U*>(0) ) ] );

  // "..." provides fallback in case above fails
  template<typename U> static no& test(...);

  static bool const value = sizeof( test<T>( NULL ) ) == sizeof( yes );
};

ただし、これに含まれる洗練度には疑問を持たざるを得ません。互いに衝突する非直交メカニズム ( to_stringvs. operator<<) が見られ、不十分な仮定が投げかけられているのを耳にします (たとえば、operator<<実装されたコードはその点で問題ないように見えますが、それはグローバル vs メンバーです)。

于 2011-04-24T04:01:18.073 に答える