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

How to enable a protected method by type

本文关键字:方法 受保护 启用 何按 类型      更新时间:2023-10-16

我想在派生类中公开提供一个函数,只有当调用参数具有特殊标签时。我正在使用clang的C 14。

给出以下情况:

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 {
};

尽管UnhandledABase继承,而handler仅需要Base

如果我正确研究了您的问题,可以使用CRTP(工作版本(实现此目标:

#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;
}

另一种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 &)
   { }