5 回答
TA贡献1911条经验 获得超7个赞
是的,使用SFINAE,您可以检查给定的类是否提供某种方法。这是工作代码:
#include <iostream>struct Hello{ int helloworld() { return 0; }};struct Generic {}; // SFINAE testtemplate <typename T>class has_helloworld{ typedef char one; typedef long two; template <typename C> static one test( typeof(&C::helloworld) ) ; template <typename C> static two test(...); public: enum { value = sizeof(test<T>(0)) == sizeof(char) };};int main(int argc, char *argv[]){ std::cout << has_helloworld<Hello>::value << std::endl; std::cout << has_helloworld<Generic>::value << std::endl; return 0;}
我刚用Linux和gcc 4.1 / 4.3测试过它。我不知道它是否可以移植到运行不同编译器的其他平台
TA贡献1878条经验 获得超4个赞
这个问题很老,但是使用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
最后继承。 最后,为您提供所传递的任何类型的“值”,而无需您知道如何构建它。请注意,这只能在未评估的上下文中使用,例如,和其他。decltype
test_stream
std::declval
decltype
sizeof
请注意,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
可以使用的上下文。
TA贡献1799条经验 获得超8个赞
虽然这个问题已经有两年了,但我还是敢补充一下。希望它能澄清以前无可争议的优秀解决方案。我采用了Nicola Bonelli和Johannes Schaub的非常有用的答案,并将它们合并为一个解决方案,即恕我直言,更易读,更清晰,不需要typeof
扩展:
template <class Type>class TypeHasToString{ // This type won't compile if the second template parameter isn't of type T, // so I can put a function pointer type in the first parameter and the function // itself in the second thus checking that the function has a specific signature. template <typename T, T> struct TypeCheck; typedef char Yes; typedef long No; // A helper struct to hold the declaration of the function pointer. // Change it if the function signature changes. template <typename T> struct ToString { typedef void (T::*fptr)(); }; template <typename T> static Yes HasToString(TypeCheck< typename ToString<T>::fptr, &T::toString >*); template <typename T> static No HasToString(...);public: static bool const value = (sizeof(HasToString<Type>(0)) == sizeof(Yes));};
我用gcc 4.1.2检查了它。这个功劳主要归功于Nicola Bonelli和Johannes Schaub,如果我的回答可以帮助你,请给他们一个投票:)
- 5 回答
- 0 关注
- 654 浏览
添加回答
举报