检查是否存在C ++成员函数,可能受保护

我试图检测一个类是否有一个特定的函数(具体来说是std::enable_shared_from_this<Some Unknown Class> shared_from_this() ,它是从std::enable_shared_from_this<Some Unknown Class>inheritance的)。 为了使事情更加复杂,我需要知道它是否具有这个function,即使它是从远处的基类inheritance的,或者是使用受保护的访问inheritance的。

我已经看过其他问题,比如这个 ,但是提供的方法不适用于检测受保护的成员函数。

目前我正在使用的方法如下:

 template <class T> struct shared_from_this_wrapper : public T { template <class U> static auto check( U const & t ) -> decltype( t.shared_from_this(), std::true_type() ); static auto check( ... ) -> decltype( std::false_type() ); }; template<class T> struct has_shared_from_this : decltype(shared_from_this_wrapper<T>::check(std::declval<shared_from_this_wrapper<T>>())) { }; 

我目前的解决scheme的缺陷是,它不适用于final宣布的类。 所以我在testing一个满足以下条件的成员函数的解决scheme之后:

  1. final声明的类一起工作
  2. 使用受保护的成员函数
  3. 与inheritance一起工作
  4. 不需要知道函数的返回types
  5. 在gcc,clang和MSVC 2013下编译(最后一个可能会限制SFINAE)

编辑:我有一个潜在的解决scheme,但需要结交一个帮助类,这也不是一个理想的解决scheme,但可能是现在的解决方法(因为它满足所有要求):

 struct access { template <class T> static auto shared_from_this( T const & t ) -> decltype( t.shared_from_this() ); }; template <class U> static auto check( U const & t ) -> decltype( access::shared_from_this(t), std::true_type() ); static auto check( ... ) -> decltype( std::false_type() ); template<class T> struct has_shared_from_this2 : decltype(check(std::declval<T>())) { }; struct A : std::enable_shared_from_this<A> {}; struct B : protected A { friend class access; }; 

另一个编辑:类的例子和types特征检查shared_from_this的存在应该返回:

 struct A : std::enable_shared_from_this<A> {}; // should return true struct B final : protected A {}; // should return true struct C : A {}; // should return true struct D {}; // should return false 

我应该提到,检测此函数是否存在的最终目标是确定它的返回types,以便找出std::enable_shared_from_this被模板化的types。 inheritance自std::enable_shared_from_this<T>给你std::shared_ptr<T> shared_from_this() ,而T最终是我需要弄清楚的。 这对于从std::enable_shared_from_thisinheritance的types的正确序列化是必需的。

编辑第3部分:编辑:

这是为了序列化库谷物而做的,因此我对用户如何devise他们的类没有任何控制。 我希望能够序列化从std::enable_shared_from_this派生的任何用户types,其中包括声明他们的类作为最终的或用途保护inheritance的用户。 任何需要插入被检查的实际types的解决scheme都不是有效的解决scheme。

我已经对如何实现你所要求的东西提出了一些想法,并得出了一个完全不同的结论。

现在的问题非常有趣:我如何检查一个类是否实现了一个隐藏的接口。 不幸的是,这个问题与利斯科夫替代原则相矛盾。 面向对象的核心原则之一。

这部分是由于std::shared_ptr的types结构。 shared_ptr不反映其参数types的inheritance关系。 给定一个类T和一个类U ,其中class T : public U {}; 保存shared_ptr<T> : public shared_ptr<U> {};

你的实现在界面层面有一个基本的缺陷。 如果您正在编译时查看函数是否存在,然后提取types,则只能对使用共享指针的数据结构进行反序列化。

此外,如果std::shared_ptr被弃用,或者你想使用其他方法获取内存( std::allocator接口?一些区域/池分配),你将不得不调整你的接口。

我个人的观点是创build某种工厂接口并将其注册到解串器的某个地方。

第二个是拥有一个暴露隐式模板接口的工厂类(并使用CRTP来专门化接口以满足用户需求,即:

 template <class ActualType, class IfType=ActualType, class Allocator=default::allocator<ActualType>> class Deserializable { static IfType alloc(ActualType &&t) { Allocator a; // choose another interface as your please. return a.allocate(t); /* implement me */ } private: }; class MyClass : public InterfaceClass, public Deserializable<MyClass,InterfaceClass> { /* your stuff here */ }; 
  • 这给你一个合理的抽象模板类。
  • 你的图书馆的用户无论如何都知道他想要什么。 如果他select分配除std::shared_ptr之外的其他东西(通过创build他自己的Allocator
  • 用户不必执行任何操作,只需要指定types(实际上将它们传递给你,所以不用再次猜测)。

你可以把这个解释为一个政策课(不是Andrei Alexandrescu的严格意义上的)。 序列化库要求分配策略。 用户可以决定如何实施这项政策。 在这种情况下,select如何分配反序列化的对象types ,这可能是不同的。 因为分配器有一个默认的实现,并且是一个模板参数,所以如果需要,另一个select被传递给用户。

为了理解这种方法的强大function,欢迎您查看boost::operator的代码,它使用这种技术在编译时指定算术运算符的返回types和参数。

注意

对于也在这个post寻找原始问题的答案的人,我build议使用这种方法 。 然而,它要求成员公开,因为它检查给定名称的成员函数指针。

我想冒昧地质疑这个问题。 并非每个通过shared_ptr传递的对象都inheritance自enable_shared_from_this。

也许这将是你正在寻找或提供一些进一步的想法:

 class Foo1 { }; class Foo2 : public std::enable_shared_from_this< Foo2 > {}; class Foo3 final : protected Foo2 {}; struct Serialize { template <typename T> void write( T* ) { printf( "not shared!\n" ); } template <typename T> void write( std::shared_ptr<T> ) { printf( "shared!\n" ); } }; int test( ) { typedef std::shared_ptr<Foo2> Foo2Ptr; typedef std::shared_ptr<Foo3> Foo3Ptr; Serialize s; Foo1* pFoo1 = nullptr; Foo2Ptr pFoo2; Foo3Ptr pFoo3; s.write( pFoo1 ); s.write( pFoo2 ); s.write( pFoo3 ); return 0; } 

在运行时,输出是:

 not shared! shared! shared! 

如果唯一的目标是检测typesT,那么我build议你喜欢在STL中添加一个typedef:

 template <class T> struct enable_shared_from_this : public T { typedef T base_type; // ... }; 

那么你可以像这样使用它:

 class A : enable_shared_from_this<B> { } A::base_type // == B 

这个例子假设你知道 A从shared_from_this_wrapperinheritance。