检测特定 C++ 类型是否具有成员,不包括继承的成员
Detect if a specific C++ type has a member, EXCLUDING inherited members
我想检测特定类型是否有成员:直接和不是继承的结果。
目的是判断一个特定类型'has a trait'是否能够序列化。当然,为了扩展示例,即使父类型可以,子类型也可能不具备序列化能力。
- 是否有(如果有)针对此请求的 "standard" 解决方案?
- 底部显示的不可转换指针方法是否存在缺陷(不包括它强加的限制)?
当使用 is_member_function_pointer
或其他检测机制时,继承在发挥作用。请注意,即使 B 未定义成员,输出也是“1”。
#include <type_traits>
#include <iostream>
struct A {
void member() { }
};
struct B : A {
};
int main()
{
std::cout << "B has member? "
<< std::is_member_function_pointer<decltype(&B::member)>::value
<< std::endl;
}
我能实现的最接近的是使用不可转换指针(B**
没有到 A**
的隐式转换),尽管使用起来有点尴尬。它还强加了与类型匹配的附加参数并防止任何直接继承。
#include <type_traits>
#include <iostream>
struct A {
// would match std::declval<B*> as B* -> A*,
// hence forcing failure through B** -> A**.
// void member(A*) { }
void member(A**) { }
};
struct B : A {
// succeeds compilation aka "found" if not commented
// void member(B**) { }
};
int main()
{
// This actually fails to compile, which is OKAY because it
// WORKS when used with SFINAE during the actual detection.
// This is just a simple example to run.
// error: invalid conversion from 'B**' to 'A**'
std::cout << "B has member? "
<< std::is_member_function_pointer<
decltype(std::declval<B>().member(std::declval<B**>()))
>::value
<< std::endl;
}
这可能对你有用:
#include <type_traits>
#include <iostream>
struct A {
void member(A**)
{}
};
struct B : A
{};
template <typename, typename = void>
struct hasMember : std::false_type {};
template <typename T>
struct hasMember<T, std::void_t<decltype(std::declval<T*>()->member())>>
: std::is_same<decltype(std::declval<T*>()->member()), void>
{};
int main() {
std::cout << "B has member ? "
<< hasMember<B>::value
<< std::endl;
}
输出将是 B has member ? 0
。
看看live
有一个巧妙的技巧可以帮助解决这个问题。
&B::member
的类型实际上是void (A::*)()
,而不是void (B::*)()
(如果member
是继承的)。
使用 SFINAE 检查 &B::member
是否存在 并且 具有正确的类型:
template <typename T, typename = void>
struct has_member : std::false_type {};
template <typename T> struct has_member
<T, std::enable_if_t<std::is_same_v<void (T::*)(), decltype(&T::member)>>>
: std::true_type
{};
这仅适用于一种特定的成员类型(member
必须是 void member()
)。将它概括为任何类型留作 reader.
的练习。
或者你可以想象并使用 void (B::*)()
由于某种原因不能隐式转换为 void (A::*)()
的事实,特别是在传递模板参数时:
template <typename T, T>
struct detect_member_helper {};
template <typename T>
using detect_member = detect_member_helper<void (T::*)(), &T::member>;
template <typename T>
inline constexpr bool has_member = std::experimental::is_detected_v<detect_member, T>;
利用 &B::member
是 void (A::*)()
这一事实,你可能会
template <typename C, typename Sig>
struct classMember : std::false_type{};
template <typename C, typename Ret, typename ... Ts>
struct classMember<C, Ret (C::*)(Ts...)> : std::true_type{};
// and other specialization for cv and ref and c ellipsis
template <typename, typename = void>
struct hasMember : std::false_type {};
template <typename T>
struct hasMember<T, std::enable_if_t<classMember<T, decltype(&T::member)>::value>> : std::true_type
{};
我想检测特定类型是否有成员:直接和不是继承的结果。
目的是判断一个特定类型'has a trait'是否能够序列化。当然,为了扩展示例,即使父类型可以,子类型也可能不具备序列化能力。
- 是否有(如果有)针对此请求的 "standard" 解决方案?
- 底部显示的不可转换指针方法是否存在缺陷(不包括它强加的限制)?
当使用 is_member_function_pointer
或其他检测机制时,继承在发挥作用。请注意,即使 B 未定义成员,输出也是“1”。
#include <type_traits>
#include <iostream>
struct A {
void member() { }
};
struct B : A {
};
int main()
{
std::cout << "B has member? "
<< std::is_member_function_pointer<decltype(&B::member)>::value
<< std::endl;
}
我能实现的最接近的是使用不可转换指针(B**
没有到 A**
的隐式转换),尽管使用起来有点尴尬。它还强加了与类型匹配的附加参数并防止任何直接继承。
#include <type_traits>
#include <iostream>
struct A {
// would match std::declval<B*> as B* -> A*,
// hence forcing failure through B** -> A**.
// void member(A*) { }
void member(A**) { }
};
struct B : A {
// succeeds compilation aka "found" if not commented
// void member(B**) { }
};
int main()
{
// This actually fails to compile, which is OKAY because it
// WORKS when used with SFINAE during the actual detection.
// This is just a simple example to run.
// error: invalid conversion from 'B**' to 'A**'
std::cout << "B has member? "
<< std::is_member_function_pointer<
decltype(std::declval<B>().member(std::declval<B**>()))
>::value
<< std::endl;
}
这可能对你有用:
#include <type_traits>
#include <iostream>
struct A {
void member(A**)
{}
};
struct B : A
{};
template <typename, typename = void>
struct hasMember : std::false_type {};
template <typename T>
struct hasMember<T, std::void_t<decltype(std::declval<T*>()->member())>>
: std::is_same<decltype(std::declval<T*>()->member()), void>
{};
int main() {
std::cout << "B has member ? "
<< hasMember<B>::value
<< std::endl;
}
输出将是 B has member ? 0
。
看看live
有一个巧妙的技巧可以帮助解决这个问题。
&B::member
的类型实际上是void (A::*)()
,而不是void (B::*)()
(如果member
是继承的)。
使用 SFINAE 检查 &B::member
是否存在 并且 具有正确的类型:
template <typename T, typename = void>
struct has_member : std::false_type {};
template <typename T> struct has_member
<T, std::enable_if_t<std::is_same_v<void (T::*)(), decltype(&T::member)>>>
: std::true_type
{};
这仅适用于一种特定的成员类型(member
必须是 void member()
)。将它概括为任何类型留作 reader.
或者你可以想象并使用 void (B::*)()
由于某种原因不能隐式转换为 void (A::*)()
的事实,特别是在传递模板参数时:
template <typename T, T>
struct detect_member_helper {};
template <typename T>
using detect_member = detect_member_helper<void (T::*)(), &T::member>;
template <typename T>
inline constexpr bool has_member = std::experimental::is_detected_v<detect_member, T>;
利用 &B::member
是 void (A::*)()
这一事实,你可能会
template <typename C, typename Sig>
struct classMember : std::false_type{};
template <typename C, typename Ret, typename ... Ts>
struct classMember<C, Ret (C::*)(Ts...)> : std::true_type{};
// and other specialization for cv and ref and c ellipsis
template <typename, typename = void>
struct hasMember : std::false_type {};
template <typename T>
struct hasMember<T, std::enable_if_t<classMember<T, decltype(&T::member)>::value>> : std::true_type
{};