评估 class 是否已从 CRTP-Base 派生模板成员函数

Evaluate whether class has derived templated-member function from CRTP-Base

以下场景:

template <typename Derived>
    class TBase
{
    public:
        TBase() = default;
        ~TBase() = default;

        bool foo() noexcept
        {
            static_assert(&Derived::foo != &TBase<Derived>::foo, "foo missing in derived class.");
            return false; // dead-line
        }

        template <typename Bla>
        bool bar(Bla bla) noexcept
        {
            static_assert(&Derived::bar!= &TBase<Derived>::bar, "foo missing in derived class.");
            return false; // dead-line
        }
};



class TDerived : public TBase<TDerived>
    {
    public:

        TDerived () noexcept = default;
        ~TDerived () noexcept = default;

        bool foo() noexcept
        {
            // do something
            return false;
        }

        // bool bar(Bla bla) noexcept -> is not implemented
    };

int main()
{
    TDerived drvd;
    drvd.bar(2);
    return 0;
}

https://onlinegdb.com/BkU4IrTBL

我收到编译器错误(可能是编译器无法推断类型):

Severity Code Description Project File Line Suppression State Error C2568 '!=': unable to resolve function overload

我能做的就是删除

template <typename PODType> bool protectData(PODType f_buf) noexcept = delete;

但我想 - 如果可能的话 - 我更喜欢 static_assert 的方法。我怎样才能做到这一点?

问题是 bar 从来都不是一个函数,它是一个函数模板。如果我稍微更改有问题的行,static_assert 有效:

template <typename T>
bool bar(T obj) noexcept {
  static_assert(&Derived::bar != &TBase<Derived>::template bar<T>,
    "bar missing in derived class.");
  return false; // dead-line
}

但是,该断言总是会失败,因为它明确地将 "regular" 函数与函数模板进行了比较。

我通过使用 static_cast:

显式消除函数指针的歧义来让它工作
template <typename T>
bool bar (T obj) noexcept {
  static_assert(
      static_cast<bool (Derived::*)(T)>(&Derived::bar)
        != static_cast<bool (TBase<Derived>::*)(T)>(&TBase<Derived>::bar)
    , "bar missing in derived class.");
  return false; // dead-line
}

但是,您还明确需要从 TDerived 中的 TBase 引入模板化 bar 函数:

class TDerived : public TBase<TDerived> { 
  public:
    using TBase<TDerived>::bar;
};