C++ 检测特定的C++;类型有一个成员,继承的成员除外

C++ 检测特定的C++;类型有一个成员,继承的成员除外,c++,inheritance,c++14,detection,typetraits,C++,Inheritance,C++14,Detection,Typetraits,我想检测特定类型是否有成员:直接而不是继承的结果 #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**)

我想检测特定类型是否有成员:直接而不是继承的结果

#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; 
}
目的是确定特定类型是否具有诸如序列化能力之类的特性。当然,为了扩展示例,即使父类型具有序列化功能,子类型也可能没有序列化功能

  • 是否有(如果有)针对该请求的“标准”解决方案
  • 底部显示的不可转换指针方法是否存在缺陷(不包括其施加的限制)
当使用
is\u member\u function\u 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; 
}

这可能适合您:

#包括
#包括
结构A{
无效成员(A**)
{}
};
结构B:A
{};
模板
结构hasMember:std::false_type{};
模板
结构hasMember>
:std::is_samemember()),void>
{};
int main(){

std::cout有一个巧妙的技巧可以帮助解决这个问题

&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
{};

使用
&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
{};
模板
结构类成员:std::false_type{};
模板
结构类成员:std::true_type{};
//以及cv、ref和c省略号的其他专门化
模板
结构hasMember:std::false_type{};
模板
结构hasMember:std::true\u类型
{};

这是否回答了您的问题?您可以要求传递给函数的内容专门化您为库创建的某些类型特征,而不是试图检测成员的存在,然后您可以检查类型特征的结果。@胡桃夹子不,它不会-除非隐藏了详细信息。该答案/问题不处理继承,这就是这个问题产生的原因。@NathanOliver对于“不引人注目的形式”也做了同样的事情:)我希望对于“突兀的/内联的”形式也能得到类似的效果。@BasileStrynkevitch所以现在我只需要为Clang、GCC、IIC、NVCC等编写、安装和维护插件;-)[Pro-Tip]
((T*)nullptr)
可以替换为
std::declval()
谢谢。原始代码中的代码就是这样被有效地使用的(例如,SFINAE/检测器被删除)。但是,它仍然依赖于不可转换的指针/非重写方法来运行。它在这里是可行的。只希望可以在不需要此类方法的情况下进行推断。它实际上不起作用。请检查example@NutCracker那是因为它需要一个不同的
成员签名
:@HolyBlackCat哇,那..行了!我无法想象昨天我们知道了如何在
中工作是一样的。注意到“类型的&B::成员实际上是无效的(A::*)()”,这也是非常简单的。一些小垫片和工作在clang3.9.1中(是的,旧的,它是我们的一个..基线..目标)。
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
{};