检查是否存在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之后:
- 与
final
声明的类一起工作 - 使用受保护的成员函数
- 与inheritance一起工作
- 不需要知道函数的返回types
- 在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_this
inheritance的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_wrapper
inheritance。