[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实现为例