Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
790 views
in Technique[技术] by (71.8m points)

c++ - SFINAE To detect non-member function existence

Does anybody know of a method for specializing a template depending on whether a non-member method is defined? I know there are numerous ways for specializing if a member function exists, but I've never seen a non-member example. The specific problem is specializing the operator<< for shared_ptr to apply the operator<< if the operator<< is defined for T, and printing the mere pointer location otherwise. It would be great if all classes defined operator<< as a member, but unfortunately many use free functions. I'm imagining something like the following:

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>";
}

Edit: For posterity, here was the working solution. Note that boost::shared_ptr already has a default operator<< that outputs the address, so the disable_if is unnecessary. Since the operator<< returns a reference, this works. For the general case I suspect this would have to be tailored to reflect the return type of the function in question.

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>";
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you are using C++0x, you could simply use decltype.

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

That'll certainly cause a substitution failure if a T cannot be output. You could probably do something similar in C++03, but I'm not sure how.

Edit: Just realised that the decltype expression doesn't actually produce a true or false value and won't compile. But you get the picture. Try this.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...