如何按类型启用受保护的方法

时间:2017-04-30 08:52:41

标签: c++ c++14 template-meta-programming

我想在派生类中公开提供一个函数,只有当调用参数有一个特殊标记时。我正在使用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继承自Basehandler只需要Base

2 个答案:

答案 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 &)
   { }