SFINAE - 尝试确定模板类型是否具有带有'variable'返回类型的成员函数 [英] SFINAE - Trying to determine if template type has member function with 'variable' return type
问题描述
使用SFINAE时遇到问题。我需要能够确定一个类型是否有一个成员函数operator-> defined,而不管它的返回类型。示例如下。
Having trouble with SFINAE. I need to be able to determine if a Type has a member function operator-> defined regardless of its return type. Example follows.
这个类在测试者中。它定义了operator - >(),返回类型为X *。因此,我不知道在任何地方都要用'X'来硬编码。
This class in the tester. It defines operator->() with a return type of X*. I thus will not know what 'X' is to hardcode it everywhere.
template <class X>
class PointerX
{
...
X* operator->() const;
...
}
此类尝试确定传入的T有一个方法operator-> defined;而不管什么operator-> return类型。
This class tries to determines if the passed in T has a method operator-> defined; regardless of what operator-> return type is.
template<typename T>
struct HasOperatorMemberAccessor
{
template <typename R, typename C> static R GetReturnType( R ( C::*)()const);
template<typename U, typename R, R(U::*)()const> struct SFINAE{};
template<typename U> static char Test(SFINAE<U, decltype( GetReturnType(&U::operator->)), &U::operator-> >*);
template<typename U> static uint Test(...);
static const bool value = sizeof(Test<T>(0)) == sizeof(char);
};
这个类与上面完全相同,除了operator-> return类型必须是Object 。
This class is the exact same as above except that operator-> return type has to be 'Object'.
template<typename T>
struct HasOperatorMemberAccessorOBJECT
{
template <typename R, typename C> static R GetReturnType( R ( C::*)()const);
template<typename U, typename R, R(U::*)()const> struct SFINAE{};
template<typename U> static char Test(SFINAE<U, Object*, &U::operator-> >*); // only change is we hardcoded Object as return type.
template<typename U> static uint Test(...);
static const bool value = sizeof(Test<T>(0)) == sizeof(char);
};
结果:
void main()
{
HasOperatorMemberAccessor<PointerX<Object>>::Test<PointerX<Object>>(0); // fails ::value is false; Test => Test(...)
HasOperatorMemberAccessorOBJECT<PointerX<Object>>::Test<PointerX<Object>>(0); // works! ::value is true; Test => Test(SFINAE<>*)
}
HasOperatorMemberAccessor无法找到PointX的成员函数Object operator - >()const。
所以它使用Test的通用版本Test(...)。
HasOperatorMemberAccessor was unable to find PointX's member function "Object operator->() const". So it uses Test's generic version Test(...).
但是,HasOperatorMemberAccessorOBJECT能够找到PointX的Object operator - >
因此它使用测试专用版本测试(SFINAE *)。
However, HasOperatorMemberAccessorOBJECT was able to find PointX's "Object operator->() const". Thus it uses Test specialized version Test(SFINAE*).
两个应该能够找到对象操作符 - >因此都应该使用Test的专业版Test(SFINAE *);因此HasOperatorMemberAccessor> :: value应该为true。
Both should have been able to find the "Object operator->() const" method; and thus both should use Test's specialized version Test(SFINAE*); and thus HasOperatorMemberAccessor>::value should be true for both.
HasOperatorMemberAccessor和HasOperatorMemberAccessorOBJECT之间的唯一区别是HasOperatorMemberAccessorOBJECT具有对对象硬编码的类型名R,
The only difference between HasOperatorMemberAccessor and HasOperatorMemberAccessorOBJECT is that HasOperatorMemberAccessorOBJECT has the typename R hardcoded to object,
问题是decltype(GetReturnType(& U :: operator->))没有正确返回Object。我试过了一些不同的许可证发现的返回类型。它们如下:
So the issue is that "decltype( GetReturnType(&U::operator->))" is not returning Object correctly. I've tried a number of different permitations of discovering the return type. They go as follows:
decltype( GetReturnType(&U::operator->) )
typename decltype( GetReturnType(&U::operator->))
decltype( ((U*)nullptr)->operator->() )
typename decltype( ((U*)nullptr)->operator->() )
我正在使用MSVC ++ 10.0。
None work, why? I'm using MSVC++ 10.0.
推荐答案
你问的是如何实现这样的trait, decltype 不符合您的期望?如果是前者,这里有一种方法:
Are you asking how to implement such a trait, or why decltype
isn't behaving as you expect? If the former, here's one approach:
#include <type_traits>
template<typename T, bool DisableB = std::is_fundamental<T>::value>
struct HasOperatorMemberAccessor
{
private:
typedef char no;
struct yes { no m[2]; };
struct ambiguator { char* operator ->() { return nullptr; } };
struct combined : T, ambiguator { };
static combined* make();
template<typename U, U> struct check_impl;
template<typename U>
static no check(
U*,
check_impl<char* (ambiguator::*)(), &U::operator ->>* = nullptr
);
static yes check(...);
public:
static bool const value=std::is_same<decltype(check(make())), yes>::value;
};
// false for fundamental types, else the definition of combined will fail
template<typename T>
struct HasOperatorMemberAccessor<T, true> : std::false_type { };
// true for non-void pointers
template<typename T>
struct HasOperatorMemberAccessor<T*, false> :
std::integral_constant<
bool,
!std::is_same<typename std::remove_cv<T>::type, void>::value
>
{ };
template<typename X>
struct PointerX
{
X* operator ->() const { return nullptr; }
};
struct X { };
int main()
{
static_assert(
HasOperatorMemberAccessor<PointerX<bool>>::value,
"PointerX<> has operator->"
);
static_assert(
!HasOperatorMemberAccessor<X>::value,
"X has no operator->"
);
static_assert(
HasOperatorMemberAccessor<int*>::value,
"int* is dereferencable"
);
static_assert(
!HasOperatorMemberAccessor<int>::value,
"int is not dereferencable"
);
static_assert(
!HasOperatorMemberAccessor<void*>::value,
"void* is not dereferencable"
);
}
VC ++ 2010缺少必要的C ++ 11设施使这更清洁。
VC++ 2010 lacks the necessary C++11 facilities (e.g. expression SFINAE) needed to make this much cleaner.
这篇关于SFINAE - 尝试确定模板类型是否具有带有'variable'返回类型的成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!