[c++] c++17 在编译期判断是否存在某个函数

Posted adream307

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[c++] c++17 在编译期判断是否存在某个函数相关的知识,希望对你有一定的参考价值。

#include <bits/stdc++.h>

namespace detail {
template <class Default, class AlwaysVoid, template <class...> class Op,
          class... Args>
struct detector {
    using value_t = std::false_type;
    using type = Default;
};

template <class Default, template <class...> class Op, class... Args>
struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
    // Note that std::void_t is a C++17 feature
    using value_t = std::true_type;
    using type = Op<Args...>;
};

}  // namespace detail

struct nonesuch {
    ~nonesuch() = delete;
    nonesuch(nonesuch const&) = delete;
    void operator=(nonesuch const&) = delete;
};

template <template <class...> class Op, class... Args>
using is_detected =
    typename detail::detector<nonesuch, void, Op, Args...>::value_t;

template <template <class...> class Op, class... Args>
using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;

template <class Default, template <class...> class Op, class... Args>
using detected_or = detail::detector<Default, void, Op, Args...>;

template <template <class...> class Op, class... Args>
constexpr bool is_detected_v = is_detected<Op, Args...>::value;

struct Detectors {
    template <typename T, typename Arg>
    using handle_t = decltype(std::declval<T>().handle(std::declval<Arg>()));
    template <typename T, typename Arg>
    using op_t = decltype(std::declval<T>()(std::declval<Arg>()));
};

template <typename TDerived>
struct Base : public Detectors {
    template <typename T>
    void entrance(const T& t) {
        if constexpr (is_detected_v<handle_t, TDerived, T>) {
            static_cast<TDerived*>(this)->handle(t);
        } else if constexpr (is_detected_v<op_t, TDerived, T>) {
            (*static_cast<TDerived*>(this))(t);
        } else {
            std::cout << "default handler, type = " << typeid(t).name()
                      << std::endl;
        }
    }
};

class D1 : public Base<D1> {
   public:
    void handle(const int& x) {
        std::cout << "D1, int handle, x = " << x << std::endl;
    }
};

class D2 : public Base<D2> {
   public:
    void operator()(const std::string& str) {
        std::cout << "D2, string handle, str = " << str << std::endl;
    }
};

struct ValueBase {};

struct IntValue : public ValueBase {
    int val;
};

struct StrValue : public ValueBase {
    std::string str;
};

class D3 : public Base<D3> {
   public:
    void handle(const ValueBase& val) {
        std::cout << "D3, value base handler" << std::endl;
    }
    void handle(const StrValue &val) {
        std::cout << "D3, str value handler, str = " << val.str << std::endl;
    }
};

int main() {
    D1 d1;
    d1.entrance(int(10));
    d1.entrance(std::string("123"));

    D2 d2;
    d2.entrance(int(10));
    d2.entrance(std::string("123"));

    D3 d3;
    IntValue iv;
    StrValue sv;
    sv.str = "123";
    d3.entrance(iv);
    d3.entrance(sv);

    return 0;
}

程序输出

D1, int handle, x = 10
default handler, type = Ss
default handler, type = i
D2, string handle, str = 123
D3, value base handler

基类 Base 定义了入口函数 entrance,如果子类定义了针对特定类型的处理函数 handle,则调用子类处理函数,否则直接调用基类的 else 分支。

因为 D1 定义类针对 int的处理函数,所以 d1.entrance(int(10) 最后调用 D1::handle(const int &),同样道理应为 D1 未定义针对 std::string 的处理函数,所以 d1.entrance(std::string(10)) 最后调用基类的 else分支代码

参考资料

以上是关于[c++] c++17 在编译期判断是否存在某个函数的主要内容,如果未能解决你的问题,请参考以下文章

[c++] c++17 在编译期判断是否存在某个函数

[c++] c++17 在编译期判断是否存在某个函数

[c++] c++17 在编译期判断是否存在某个函数

C++模板进阶指南:SFINAE

C++编译期反射实践——以AOP实现为例

C++编译期反射实践——以AOP实现为例