如何enable/disable一个成员函数根据其存在的成员派生class?

How to enable/disable a member function according to the existence of a member of its derived class?

我搜索了 10 多个答案,没有一个符合我目前的情况。

(member detector marcos 来自:http://en.wikibooks.org/wiki/More_C++_Idioms/Member_Detector)

CREATE_MEMBER_DETECTOR(normal);
CREATE_MEMBER_DETECTOR(abnormal);

template <typename T>
struct Weapon
{
    //template <std::enable_if_t<Detect_normal<T>::value, T>* = nullptr>
    template <std::enable_if_t<Detect_abnormal<T>::value, bool> = true>
    void DefaultShoot()
    {
        std::cout << "special\n";
    }

    template <std::enable_if_t<Detect_normal<T>::value, bool> = true>
    void DefaultShoot()
    {
        std::cout << "general\n";
    }
};

struct FOO : public Weapon<FOO>
{
    static constexpr auto normal = 10;

    virtual void Shoot() { DefaultShoot(); }
};

预期:模板根据我在子类中的constexpr生成一组函数。
现实:产生一堆错误,一直没有编译成功...

有没有人知道是否可以在 C++17 中执行此操作?

编辑:“其他”在我的情况下是否可行? 这其实也是我的初衷。

template <typename T>
struct Weapon
{
    template <std::enable_if_t<Detect_abnormal<T>::value, bool> = true>
    void DefaultShoot()
    {
        std::cout << "special\n";
    }

    //template <std::enable_if_t<Detect_normal<T>::value, bool> = true>
    #some magical "else" code if the one above is invalidated.
    void DefaultShoot()
    {
        std::cout << "general\n";
    }
};

您需要 SFINAE 方法中的模板参数:

template <typename T>
struct Weapon
{
    template <typename U = T, std::enable_if_t<Detect_abnormal<U>::value, bool> = true>
    void DefaultShoot()
    {
        std::cout << "special\n";
    }

    template <typename U = T, std::enable_if_t<Detect_normal<U>::value, bool> = true>
    void DefaultShoot()
    {
        std::cout << "general\n";
    }
};

请注意,如果两者同时为真,您将有歧义调用。

在 C++17 中,您可以使用 if constexpr:

template <typename T>
struct Weapon
{
    void DefaultShoot()
    {
        if constexpr (Detect_abnormal<T>::value) {
            std::cout << "special\n";
        } else if constexpr (Detect_normal<T>::value) {
            std::cout << "general\n";
        } // else {}
    }
};

C++20 将允许在其 requires:

中使用 class 模板参数
template <typename T>
struct Weapon
{
    void DefaultShoot() requires(Detect_abnormal<T>::value)
    {
        std::cout << "special\n";
    }

    void DefaultShoot() requires(Detect_normal<T>::value)
    {
        std::cout << "general\n";
    }
};

请注意,如果两者同时为真,您将有歧义调用。

仅供参考,您可以在 C++17 中使用更简单的检测器:

#define CREATE_MEMBER_DETECTOR(X) \
    template <typename T, typename = void> \
    struct Detect_ ## X : std::false_type {}; \
\
    template <typename T>\
    struct Detect_ ## X<T, std::void_t<decltype(T::X)> > \
        : std::true_type {};