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

通过迭代器/指针访问命名空间?

  •  2
  • insipidintegrator  · 技术社区  · 6 月前

    我目前面临着某种设计/语言问题。我有3个文件,A、B和C,它们分别有自己的命名空间定义为A、B、C。每个名称空间都有完全相同的函数签名,只是实现方式不同(想想使用不同但相似的API的REST API调用)。
    现在,我的目标是能够从正确的名称空间调用这些函数,而无需重复函数名。

    理想情况下,我想做这样的事情:

    #include <iostream>
    
    #include "A.h"
    #include "B.h"
    #include "C.h"
    
    enum ns {
        A = 0,
        B = 1,
        C = 2
    };
    int main() {
    
        auto NS = {A, B, C}; //these are the namespaces
    
        if (condition){
            int n = get_index();
            NS[n]::myfunc();
        }
    }
    

    哪里 myfunc() 在与A.h、B.h和C.h对应的每个源文件中定义不同。

    有人能告诉我是否有办法做到这一点,或者建议我应该采用另一种设计模式吗?谢谢

    为了更具体地解释我的问题,我有一个 DataReader 类,它从供应商A、B、C的REST端点获取有关汽车的数据并对其进行预处理。我确实想过为不同的供应商创建一个类并将其子类化,但如果在我的内部有一个特定于供应商的类,那岂不是太复杂了 DataReader 班级?

    3 回复  |  直到 6 月前
        1
  •  5
  •   wohlstad    6 月前

    您可以使用纯虚方法创建基类/结构体 myfunc() ,
    然后制作 A , B C (如果你想的话,每个都可以驻留在它的命名空间中,但这不是必须的)从它派生并实现 myfunc .

    然后,您可以将它们全部存储在一个数组中,并使用多态调用基于索引调用适当的方法:

    #include <array>
    #include <iostream>
    #include <memory>
    
    struct Base {
        virtual ~Base() = default;
        virtual void myfunc() = 0;
    };
    
    namespace AAA   // using a namespace is optional
    {
        struct A : public Base {
            void myfunc() override { std::cout << "A::myfunc()\n"; }
        };
    }
    
    namespace BBB   // using a namespace is optional
    {
        struct B : public Base {
            void myfunc() override { std::cout << "B::myfunc()\n"; }
        };
    }
    
    namespace CCC   // using a namespace is optional
    {
        struct C : public Base {
            void myfunc() override { std::cout << "C::myfunc()\n"; }
        };
    }
    
    int main() {
        std::array<std::unique_ptr<Base>, 3> objs = {
            std::make_unique<AAA::A>(),
            std::make_unique<BBB::B>(),
            std::make_unique<CCC::C>()
        };
    
        objs[0]->myfunc();
        objs[1]->myfunc();
        objs[2]->myfunc();
    }
    

    输出:

    A::myfunc()
    B::myfunc()
    C::myfunc()
    

    Live demo .

    笔记:

    1. 我使用的唯一原因 struct s代替 class es是使演示缩短几行(保存 public: 线)。您可以使用 当然不是他们。
    2. 我添加了名称空间,以防您想将类放在名称空间中(因为您在问题中提到了它们),尽管上面的解决方案并不真正需要它们。
        2
  •  3
  •   MarkB    6 月前

    您可以使用函数指针数组(或 std::function )通过枚举调用相应的函数。

    #include <functional>
    #include <array>
    #include <iostream>
    
    namespace NSA {
    int my_func(int x, int y) {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        return x + y;
    }
    }
    namespace NSB {
    int my_func(int x, int y) {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        return x - y;
    }
    }
    namespace NSC {
    int my_func(int x, int y) {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        return x * y;
    }
    }
    
    enum ns {
        A = 0,
        B = 1,
        C = 2
    };
    
    constexpr std::array funcs = {&NSA::my_func, &NSB::my_func, &NSC::my_func};
    
    int main()
    {
        return funcs[ns::A](10, 20);
    }
    

    如果你愿意使用宏,它们可以用来避免代码中重复的标记。以下是一个示例:

    #define PPCAT_NX(A, B) A ## B
    #define PPCAT(A, B) PPCAT_NX(A, B)
    #define DEFINE_FUNC_ARRAY(FN) constexpr std::array PPCAT(invoke_, FN) = { &NSA::FN, &NSB::FN, &NSC::FN };
    
    DEFINE_FUNC_ARRAY(my_func)
    
    int main()
    {
        return invoke_my_func[ns::A](10, 20);
    }
    
        3
  •  1
  •   Jarod42    6 月前

    如果你能转身 namespace s转换为“静态”类,然后可以使用 template :

    #include <variant>
    
    enum ns {
        A = 0,
        B = 1,
        C = 2
    };
    std::variant<
        std::type_identity<A>,
        std::type_identity<B>,
        std::type_identity<C>>
    to_variant(ns e)
    {
        switch (e) {
            case ns::A: return std::type_identity<A>{};
            case ns::B: return std::type_identity<B>{};
            case ns::C: return std::type_identity<C>{};
        }
        throw std::runtime_error("no valid enum ns");
    }
    
    int main() {
        ns n = get_index();
        std::visit([]<class T>(std::type_identity<T>){ T::myfunc(); }, to_variant(n));
    }
    

    Demo