将枚举类映射到函数重载

问题描述 投票:0回答:1

您好,我面临以下问题:我有一个类,其中包含特定模式的许多成员函数。这些成员函数中的每一个都有 3 个重载,并且这些重载对于所有考虑的成员函数都是相同的。我所说的“相同”是指除了函数名称之外它们具有相同的签名。这导致在选择所需方法的控制状态中出现大量代码重复。当添加新方法时,维护起来很麻烦。 此外,我有一个枚举类(基于无符号整数),其中每个成员函数都有一个项目。 我尝试创建从枚举类到成员函数的映射(参见下面的示例)。

示例

我有几个成员函数

memfunc1
memfunc2
、...并且我有 3 个函数(例如
caller1
caller2
caller3
),每个函数将三个重载之一的参数加上一个枚举作为参数告诉我要调用哪个 memfuncs。我想避免将枚举映射到 memfunc 三次而不是一次。我可以想象这是可能的,因为编译器知道签名,因为每个 memfunc 的重载出现在单独的控制路径中。

    enum class Algos : unsigned int {
    FUN1 = 0,
    FUN2,
    FUN3,
    NUM_OF_FUNCTIONS
};
    class Algorithms {
    Type1 memfunc1();
    Type1 memfunc1(const Type2&);
    Type1 memfunc1(Type3&, const Type2&);
    Type1 memfunc2();
    Type1 memfunc2(const Type2&);
    Type1 memfunc2(Type3&, const Type2&);
    Type1 memfunc3();
    Type1 memfunc3(const Type2&);
    Type1 memfunc3(Type3&, const Type2&);
    };

我目前所做的是

Type1 Algorithms::caller1(Algos algo) {
  if (algo == Algos::FUN1) {
    return memfunc1();
  }
  if (algo == Algos::FUN2) {
    return memfunc2();
  }
  if (algo == Algos::FUN3) {
    return memfunc3();
  }
}

Type1 Algorithms::caller2(const Type2& arg, Algos algo) {
  if (algo == Algos::FUN1) {
    return memfunc1(arg);
  }
  if (algo == Algos::FUN2) {
    return memfunc2(arg);
  }
  if (algo == Algos::FUN3) {
    return memfunc3(arg);
  }
}

Type1 Algorithms::caller3(Type3& arg1, const Type2& arg2, Algos algo) {
  if (algo == Algos::FUN1) {
    return memfunc1(arg1, arg2);
  }
  if (algo == Algos::FUN2) {
    return memfunc2(arg1, arg2);
  }
  if (algo == Algos::FUN3) {
    return memfunc3(arg1, arg2);
  }
}

但我想将从枚举到成员函数的映射与特定重载分开。因为所有三个调用函数的作用或多或少是相同的:

FUN1 -> memfunc1
FUN2 -> memfunc2
FUN3 -> memfunc3
...

以允许调用的方式:

    Type1 a = std::invoke(mapping(FUN1), const Type2&);

我并不完全依赖于使用

std::invoke
的语法,并且在调用时提供
Algorithms
的实例也完全没问题,但我希望编译器根据提供的参数选择正确的函数重载。理想情况下,映射发生在编译时,因为它是枚举,并且提供的参数在编译时是已知的。

到目前为止,我阅读了一些相关的堆栈溢出帖子,包括:

以及许多 cppreference 页面,包括 https://en.cppreference.com/w/cpp/utility/functional/mem_fn

到目前为止我的方法是创建一个数组

    using Overload2 = std::function<Type1(const Type2&)>;
    std::array<Overload2, std::to_underlying(Algos::NUM_OF_FUNCTIONS)> pMethods;

然后通过调用填充数组

    pMethods.at(std::to_underlying(Algos::FUN1)) = [this](const Type2& var) {
    return memfunc1(var);
    };

其他成员函数和重载也类似。但是,这不是理想的解决方案,因为它将代码重复移动到代码的另一部分,但没有解决它。 他们使用

std::unordered_map
的想法我在这个过程的早期就被放弃了,因为据我所知,这个容器不能很好地与
constexpr
关键字一起使用,因为它是非文字类型。我想我记得有几个 SO-posts 解决这个问题。

使用最新版本的 c++ 对我来说没问题,只要它们在 g++-14 和 clang++-18 中编译即可。我更喜欢不使用除 stl 之外的库的解决方案,并且更喜欢内存安全的 stl 解决方案而不是 c 风格的解决方案。

提前致谢!

c++ overloading signature code-duplication member-functions
1个回答
0
投票

每个调用者可以有一个数组,而不是每个实例三个。

class Algorithms {
    Type1 memfunc1();
    Type1 memfunc1(const Type2&);
    Type1 memfunc1(Type3&, const Type2&);
    Type1 memfunc2();
    Type1 memfunc2(const Type2&);
    Type1 memfunc2(Type3&, const Type2&);
    Type1 memfunc3();
    Type1 memfunc3(const Type2&);
    Type1 memfunc3(Type3&, const Type2&);
        
public:
    Type1 caller1(Algos algo) { 
        static constexpr std::array<Type1(Algorithms::*)(), std::to_underlying(Algos::NUM_OF_FUNCTIONS)> dispatch = { &Algorithms::memfunc1, &Algorithms::memfunc2, &Algorithms::memfunc3 };
        return std::invoke(dispatch[std::to_underlying(algo)], this); 
    }
    Type1 caller2(const Type2& arg, Algos algo) { 
        static constexpr std::array<Type1(Algorithms::*)(const Type2&), std::to_underlying(Algos::NUM_OF_FUNCTIONS)> dispatch = { &Algorithms::memfunc1, &Algorithms::memfunc2, &Algorithms::memfunc3 };
        return std::invoke(dispatch[std::to_underlying(algo)], this, arg); 
    }
    Type1 caller3(Type3& arg1, const Type2& arg2, Algos algo) { 
        static constexpr std::array<Type1(Algorithms::*)(Type3&, const Type2&), std::to_underlying(Algos::NUM_OF_FUNCTIONS)> dispatch = { &Algorithms::memfunc1, &Algorithms::memfunc2, &Algorithms::memfunc3 };
        return std::invoke(dispatch[std::to_underlying(algo)], this, arg1, arg2); 
    }
};
© www.soinside.com 2019 - 2024. All rights reserved.