我想在派生类中公开提供一个函数,只有当调用参数有一个特殊标记时。我正在使用C ++ 14和Clang。
Giveǹ是以下情况:
struct TagA {};
struct TagB {};
struct Base {
protected:
void handler(const std::shared_ptr<Base> &obj) {
...
}
};
目标是在派生类中使handler
可用(如果它们具有特殊标记),以允许派生对象的不同“类”。像这样:
struct DerivedA : Base, TagA {
// This should only be available, if the obj argument for handler
// derives from TagA
// something like std::enable_if<std::is_base_of<TagA, ???>::value>
using Base::handler;
};
这将允许DerivedA
处理
struct HandledA : Base, TagA {
};
但不是
struct UnhandledA : Base, TagB {
};
虽然UnhandledA
继承自Base
而handler
只需要Base
。
答案 0 :(得分:3)
如果我正确地解释了您的问题,您可以使用CRTP(working version)实现此目的:
#include <memory>
#include <type_traits>
struct TagA {};
struct TagB {};
template< typename tp_Derived > struct BaseCRTP;
struct Base
{
template< typename > friend
struct BaseCRTP;
private: void
handler_impl(const std::shared_ptr<Base> &) {}
};
template< typename tp_Derived >
struct BaseCRTP: public Base
{
public: void
handler(const std::shared_ptr<Base> & obj)
{
static_assert
(
::std::is_base_of< TagA, tp_Derived >::value
, "\"handler\" method can only be used in classes deriving from TagA"
);
return(handler_impl(obj));
}
};
struct DerivedA : BaseCRTP< DerivedA >, TagA
{};
struct DerivedB : BaseCRTP< DerivedB >, TagB
{};
int main()
{
DerivedA a; // OK
(void) a; // not used
auto pha(&DerivedA::handler); // OK
DerivedB b; // OK
(void) b; // not used
auto phb(&DerivedB::handler); // static_assertion failure
return 0;
}
答案 1 :(得分:2)
另一个CRTP解决方案可能涉及SFINAE(std::enable_if<>
)如下
#include <memory>
#include <type_traits>
struct TagA {};
struct TagB {};
template <typename Der>
struct Base
{
protected:
template <typename D = Der>
typename std::enable_if<std::is_base_of<TagA, D>::value>::type
handler (std::shared_ptr<Base> const &)
{ }
};
struct DerivedA : Base<DerivedA>, TagA
{ using Base::handler; };
struct DerivedB : Base<DerivedB>, TagB
{ using Base::handler; };
int main ()
{
DerivedA{}.handler(nullptr); // compile
DerivedB{}.handler(nullptr); // compilation error
}
为了避免使用处理程序,可能会显示模板类型,如下所示
DerivedB{}.handler<TagA>(nullptr); // now compile
您可以改善std::enable_if
测试强制,D
等于Der
template <typename D = Der>
typename std::enable_if< std::is_base_of<TagA, D>::value
&& std::is_same<D, Der>::value>::type
handler (std::shared_ptr<Base> const &)
{ }