代码之家  ›  专栏  ›  技术社区  ›  Vincent

一种类型特征,标识哪个类提供重载解析选择的函数

  •  6
  • Vincent  · 技术社区  · 7 年前

    考虑以下代码,其中一个函子 derived ,继承自两个基类 base1 base2 每个都提供不同的重载:

    // Preamble
    #include <iostream>
    #include <functional>
    #include <type_traits>
    
    // Base 1
    struct base1 {
        void operator()(int) const {
            std::cout << "void base1::operator()(int) const\n";
        }
        void operator()(double) const {
            std::cout << "void base1::operator()(double) const\n";
        }
        template <class Arg, class... Args>
        void operator()(const Arg&, Args&&...) const {
            std::cout << "void base1::operator()(const Arg&, Args&&...) const\n";
        }
    };
    
    // Base 2
    struct base2 {
        void operator()(int) {
            std::cout << "void base2::operator()(int)\n";
        }
        void operator()(double) {
            std::cout << "void base2::operator()(double)\n";
        }
    };
    
    // Derived
    struct derived: base1, base2 {
        using base1::operator();
        using base2::operator();
        void operator()(char) {
            std::cout << "void derived::operator()(char)\n";
        }
    };
    
    // Call
    template <class F, class... Args>
    void call(F&& f, Args&&... args) {
        std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
    }
    
    // Main
    int main(int argc, char* argv[]) {
        const derived d1;
        derived d2;
        derived d3;
        call(d1, 1);    // void base1::operator()(int) const
        call(d2, 1);    // void base2::operator()(int)
        call(d1, 1, 2); // void base1::operator()(const Arg&, Args&&...) const
        call(d2, 1, 2); // void base1::operator()(const Arg&, Args&&...) const
        call(d3, 'a');  // void derived::operator()(char)
        return 0;
    }
    

    结果输出为:

    void base1::operator()(int) const
    void base2::operator()(int)
    void base1::operator()(const Arg&, Args&&...) const
    void base1::operator()(const Arg&, Args&&...) const
    void derived::operator()(char)
    

    这说明根据参数,所选重载可以来自 基准1 , 二进制数字系统 派生的 .

    我的问题是 :是否可以在编译时通过创建一个类型特征来检测哪个类提供了所选的重载来执行相同的操作?

    其形式如下:

    template <
        class Base1,   // Possibly cv-ref qualified base1
        class Base2,   // Possibly cv-ref qualified base2
        class Derived, // Possibly cv-ref qualified derived
        class... Args  // Possibly cv-ref qualified args
    >
    struct overload_origin {
        using base1 = std::decay_t<Base1>;
        using base2 = std::decay_t<Base2>;
        using derived = std::decay_t<Derived>;
        using type = /* base1, base2, or derived * /
    };
    

    以及在 call 前面示例代码中的函数 overload_origin::type 参考 基准1 , 二进制数字系统 , 基准1 , 基准1 , 派生的 对于示例代码中所示的五个调用。

    如何使用模板元编程实现这样的事情?

    1 回复  |  直到 7 年前
        1
  •  3
  •   Oliv    7 年前

    您可以从 derived base1 . 这样所有呼叫 operator() 来自 基准1 将不明确:

    struct derived_check: base1, derived {
        using base1::operator();
        using base2::operator();
    };
    // Main
    int main(int argc, char* argv[]) {
        const derived_check d1;
        derived_check d2;
        derived_check d3;
        call(d1, 1);    // error:ambiguous
        call(d2, 1);    // OK
        call(d1, 1, 2); // error:ambiguous
        call(d2, 1, 2); // error:ambiguous
    
        return 0;
    }
    

    然后,您可以使用基本的检测技巧创建检测类型特征。