Mar*_*utz 29 c++ final type-traits template-meta-programming c++11
在/sf/answers/137702841/中,提供了一种解决方案,用于静态检查成员是否存在,可能在类型的子类中:
template <typename Type>
class has_resize_method
{
class yes { char m;};
class no { yes m[2];};
struct BaseMixin
{
void resize(int){}
};
struct Base : public Type, public BaseMixin {};
template <typename T, T t> class Helper{};
template <typename U>
static no deduce(U*, Helper<void (BaseMixin::*)(), &U::foo>* = 0);
static yes deduce(...);
public:
static const bool result = sizeof(yes) == sizeof(deduce((Base*)(0)));
};
Run Code Online (Sandbox Code Playgroud)
但是,它不适用于C++ 11 final
类,因为它继承了被测试的类,这会final
阻止它.
OTOH,这一个:
template <typename C>
struct has_reserve_method {
private:
struct No {};
struct Yes { No no[2]; };
template <typename T, typename I, void(T::*)(I) > struct sfinae {};
template <typename T> static No check( ... );
template <typename T> static Yes check( sfinae<T,int, &T::reserve> * );
template <typename T> static Yes check( sfinae<T,size_t,&T::reserve> * );
public:
static const bool value = sizeof( check<C>(0) ) == sizeof( Yes ) ;
};
Run Code Online (Sandbox Code Playgroud)
无法reserve(int/size_t)
在基类中找到该方法.
有没有这个元函数,它发现两者的实现reserved()
在基类T
和仍然有效,如果T
是final
?
Mat*_* M. 51
实际上,由于decltype
后期返回绑定机制,C++ 11中的事情变得更加容易.
现在,使用方法测试它更简单:
// Culled by SFINAE if reserve does not exist or is not accessible
template <typename T>
constexpr auto has_reserve_method(T& t) -> decltype(t.reserve(0), bool()) {
return true;
}
// Used as fallback when SFINAE culls the template method
constexpr bool has_reserve_method(...) { return false; }
Run Code Online (Sandbox Code Playgroud)
然后,您可以在类中使用它,例如:
template <typename T, bool b>
struct Reserver {
static void apply(T& t, size_t n) { t.reserve(n); }
};
template <typename T>
struct Reserver <T, false> {
static void apply(T& t, size_t n) {}
};
Run Code Online (Sandbox Code Playgroud)
你使用它:
template <typename T>
bool reserve(T& t, size_t n) {
Reserver<T, has_reserve_method(t)>::apply(t, n);
return has_reserve_method(t);
}
Run Code Online (Sandbox Code Playgroud)
或者您可以选择一种enable_if
方法:
template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<has_reserve_method(t), bool>::type {
t.reserve(n);
return true;
}
template <typename T>
auto reserve(T& t, size_t n) -> typename std::enable_if<not has_reserve_method(t), bool>::type {
return false;
}
Run Code Online (Sandbox Code Playgroud)
请注意,这种切换实际上并不那么容易.一般来说,只有SFINAE存在时更容易 - 你只想要enable_if
一种方法而不提供任何后备:
template <typename T>
auto reserve(T& t, size_t n) -> decltype(t.reserve(n), void()) {
t.reserve(n);
}
Run Code Online (Sandbox Code Playgroud)
如果替换失败,则从可能的重载列表中删除此方法.
注意:由于,
(逗号运算符)的语义,您可以链接多个表达式decltype
,只有最后一个实际决定类型.方便检查多个操作.
Luc*_*ton 10
一个版本也依赖decltype
但不依赖于传递任意类型(...)
[实际上这是一个非问题,请参阅约翰内斯的评论]:
template<typename> struct Void { typedef void type; };
template<typename T, typename Sfinae = void>
struct has_reserve: std::false_type {};
template<typename T>
struct has_reserve<
T
, typename Void<
decltype( std::declval<T&>().reserve(0) )
>::type
>: std::true_type {};
Run Code Online (Sandbox Code Playgroud)
我想根据这个特性指出一个类型如std::vector<int>&
支持reserve
:这里的表达式是检查的,而不是类型.这个特性所回答的问题是"给定lval
这种类型的左值T
,表达是否lval.reserve(0);
良好".与"此类型或其任何基类型是否已reserve
声明成员"这一问题不同.
另一方面,可以说这是一个特色!请记住,新的C++ 11特性是风格is_default_constructible
,而不是 has_default_constructor
.区别是微妙但有优点.(以is_*ible
左手的方式找到一个更合适的名称作为练习.)
在任何情况下,您仍然可以使用特性,例如std::is_class
可能实现您想要的.