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最后继承。 最后,为您提供所传递的任何类型的“值”,而无需您知道如何构建它。请注意,这只能在未评估的上下文中使用,例如,和其他。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可以使用的上下文。
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 关注
- 764 浏览
添加回答
举报
