如何检查类中是否存在成员名称(变量或函数),是否指定了类型?

iam*_*ind 3 c++ macros templates class member

这个Q是以下的扩展:
是否可以编写C++模板来检查函数的存在?

是否有任何有助于找到的实用程序:

  • 如果某个成员名称存在于某个类中?该成员可以是变量或方法.
  • 指定成员的类型应该是可选的

Tar*_*ama 7

有了std::experimental::is_detectedstd::experimental::disjunction你可以这样做:

//check for a type member named foo
template <typename T>
using foo_type_t = typename T::foo;

//check for a non-type member named foo
template <typename T>
using foo_non_type_t = decltype(&T::foo);

template <typename T>
using has_foo = disjunction<is_detected<foo_type_t, T>,
                            is_detected<foo_non_type_t, T>>;
Run Code Online (Sandbox Code Playgroud)

然后你可以随意使用has_foo<my_class>::value.

上面的内容不仅适用于类型和成员函数,而且您可以通过使用特征来轻松约束它std::is_member_function_pointer,std::is_member_object_pointer如果您愿意的话.

要提供可选参数,可以使用std::experimental::is_detected_exact帮助程序.

Live Demo


请注意,如果从我链接的页面中获取上述特征的实现,则可以将其与C++ 14一起使用.对disjunction代码进行微小更改将允许您在C++ 11中使用它.


iam*_*ind 2

C++03

#define HasMember(NAME) \
  template<class Class, typename Type = void> \
  struct HasMember_##NAME \
  { \
    typedef char (&yes)[2]; \
    template<unsigned long> struct exists; \
    template<typename V> static yes Check (exists<sizeof(static_cast<Type>(&V::NAME))>*); \
    template<typename> static char Check (...); \
    static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes)); \
  }; \
  template<class Class> \
  struct HasMember_##NAME<Class, void> \
  { \
    typedef char (&yes)[2]; \
    template<unsigned long> struct exists; \
    template<typename V> static yes Check (exists<sizeof(&V::NAME)>*); \
    template<typename> static char Check (...); \
    static const bool value = (sizeof(Check<Class>(0)) == sizeof(yes)); \
  }
Run Code Online (Sandbox Code Playgroud)

用法:只需使用您想要查找的任何成员调用宏即可:

HasMember(Foo);  // Creates a SFINAE `class HasMember_Foo`
HasMember(i);    // Creates a SFINAE `class HasMember_i`
Run Code Online (Sandbox Code Playgroud)

现在我们可以利用以下方式HasMember_X签入X任何内容:class

#include<iostream>
struct S
{
  void Foo () const {}
//  void Foo () {}  // If uncommented then type should be mentioned in `HasMember_Foo`    
  int i;
};
int main ()
{
  std::cout << HasMember_Foo<S, void (S::*) () const>::value << "\n";
  std::cout << HasMember_Foo<S>::value << "\n";
  std::cout << HasMember_i<S, int (S::*)>::value << "\n";
  std::cout << HasMember_i<S>::value << "\n";
}
Run Code Online (Sandbox Code Playgroud)

渔获

  1. 对于方法,如果我们不提及类型,则class 不得有重载方法。如果有,那么这个技巧就失败了。即,即使指定成员出现多次,结果也将是false
  2. 如果成员是基类的一部分,那么这个技巧就会失败;例如,如果存在&B的基数,则or或将给出Svoid B::Bar ()HasMember_Bar<S, void (B::*)()>::valueHasMember_Bar<S, void (S::*)()>::valueHasMember_Bar<S>::valuefalse