UYOU
这个问题很老,但是使用C ++ 11,我们有了一种新方法来检查函数是否存在(或者确实存在任何非类型成员),再次依赖SFINAE:template<class T>auto serialize_imp(std::ostream& os, T const& obj, int)
-> decltype(os << obj, void()){
os << obj;}template<class T>auto serialize_imp(std::ostream& os, T const& obj, long)
-> decltype(obj.stream(os), void()){
obj.stream(os);}template<class T>auto serialize(std::ostream& os, T const& obj)
-> decltype(serialize_imp(os, obj, 0), void()){
serialize_imp(os, obj, 0);}现在进行一些解释。首先,如果内部的第一个表达式无效(也就是说,函数不存在),我使用表达式SFINAEserialize(_imp)从重载解析中排除函数decltype。本void()是用来做的所有这些函数的返回类型void。如果两者都可用,则该0参数用于优先选择重载os << obj(文字0是类型的int,因此第一个重载是更好的匹配)。现在,您可能需要一个特征来检查函数是否存在。幸运的是,写起来很容易。但是请注意,您需要为自己想要的每个不同的函数名自己编写一个特征。#include <type_traits>template<class>struct sfinae_true : std::true_type{};namespace detail{
template<class T, class A0>
static auto test_stream(int)
-> sfinae_true<decltype(std::declval<T>().stream(std::declval<A0>()))>;
template<class, class A0>
static auto test_stream(long) -> std::false_type;} // detail::template<class T, class Arg>struct has_stream :
decltype(detail::test_stream<T, Arg>(0)){};实例。并解释。首先,sfinae_true是一个帮助器类型,它基本上与写入相同decltype(void(std::declval<T>().stream(a0)), std::true_type{})。优点是它更短。接下来,取决于签入是否失败,struct has_stream : decltype(...)从任一端std::true_type或std::false_type最后继承。 最后,为您提供所传递的任何类型的“值”,而无需您知道如何构建它。请注意,这只能在未评估的上下文中使用,例如,和其他。decltypetest_streamstd::declvaldecltypesizeof请注意,decltype不一定需要,因为sizeof(并且所有未评估的上下文)都获得了增强。它只是decltype已经提供了一种类型,因此只是更清洁。这是一个sizeof重载的版本:template<class T>void serialize_imp(std::ostream& os, T const& obj, int,
int(*)[sizeof((os << obj),0)] = 0){
os << obj;}由于同样的原因,int和long参数仍然存在。数组指针用于提供sizeof可以使用的上下文。