如何C++代表与操作顺序相关的状态标志?

发布于 2025-01-27 05:50:43 字数 783 浏览 2 评论 0原文

我现在正在研究运动控制系统。我想使运动控制接口更加灵活,因此我想提供一个可以指定受控轴的API。

就像。

void moveTo(/*data*/, Axis which);

轴参数用于定义应如何处理运动数据,并且内部实施将根据请求的轴检查数据。

因此,我想在轴参数上定义操作规则。

我尝试了位标志,定义为如下。

enum class Axis : std::uint_fast16_t {
    X = 1l << 0,
    Y = 1l << 1,
    Z = 1l << 2
}; 
// operator | and & and so on are also defined.

它可以用如下。

const auto which = Axis::X | Axis::Y;

但是我想要的是, axis :: x | Axis :: y Axis :: y | Axis :: X 应该有所不同,但是现在它们具有相同的价值。无法在功能中区分它们。

我应该如何定义似乎与“操作顺序”相关的蒙版?

似乎是通过在单个枚举中列出所有允许的合并状态来做到这一点。但是我仍然想问是否有更优雅和清晰的解决方案。

还是更好地实施此类功能的建议?

我希望最终用法仍然像咬面罩一样简单,我不介意我是否在幕后做一些非常复杂的工作,我不介意使用任何第三方库。

I am now working on a motion control system. I want to make the motion control interface more flexible, so I want to provide an api that can specifiy the controlled axis.

It just like.

void moveTo(/*data*/, Axis which);

Axis parameter is used to define how the motion data should be treated as and the internal implement will check the data according the requested axis.

So i want to define a operation rules on Axis parameters.

I tried the bit flags, defined as follow.

enum class Axis : std::uint_fast16_t {
    X = 1l << 0,
    Y = 1l << 1,
    Z = 1l << 2
}; 
// operator | and & and so on are also defined.

It can be used as follow.

const auto which = Axis::X | Axis::Y;

But what i want is that, Axis::X | Axis::Y and Axis::Y | Axis::X should be different, but now they have same value. There is no way to distinguish them inside the function.

How should I define such a bit mask that appears to be related to "order of operations"?

It seems to do this by listing all allowed combined states in a single enumeration. But I still want to ask if there is a more elegant and clear solution.

Or any suggestion for a better implementation of such functionality?

I hope the final usage is still as simple as the bit mask, I don't mind if I do some really complicated work behind the scenes, I don't mind using any 3rd party library.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

野心澎湃 2025-02-03 05:50:43

鉴于您只有3个轴和有限的组合,我建议只定义所有轴。

enum class Axis : std::uint_fast16_t {
    X   = 0,
    Y   = 1,
    Z   = 2,
    XX  = 3,
    YX  = 4,
    ZX  = 5,
    XY  = 6,
    YY  = 7,
    ZY  = 8,
    XZ  = 9,
    YZ  = 10,
    ZZ  = 11,
    XXX = 12,
    YXX = 13,
    ZXX = 14,
    XYX = 15,
    YYX = 16,
    ZYX = 17,
    XZX = 18,
    YZX = 19,
    ZZX = 20,
    XXY = 21,
    YXY = 22,
    ZXY = 23,
    XYY = 24,
    YYY = 25,
    ZYY = 26,
    XZY = 27,
    YZY = 28,
    ZZY = 29,
    XXZ = 30,
    YXZ = 31,
    ZXZ = 32,
    XYZ = 33,
    YYZ = 34,
    ZYZ = 35,
    XZZ = 36,
    YZZ = 37,
    ZZZ = 38,
};

如果您想以编程方式进行操作,那么您可以做的是每次添加新标志时将值移动2来制作标志,因为每个值都由2位表示。

#include <type_traits>
#include <array>
#include <iostream>
#include <bitset>


enum class Axis : std::uint_fast16_t {
    X = 0b01,
    Y = 0b10,
    Z = 0b11,
};


Axis append_flag(Axis current, Axis to_append) {
    std::uint_fast16_t flag = static_cast<std::uint_fast16_t>(current);
    flag = (flag << 2) | static_cast<std::uint_fast16_t>(to_append);
    return static_cast<Axis>(flag);
}


template <class ... T>
Axis make_flag(T ... axes) {
    std::array values = { axes... };
    auto flag = values[0];
    for (std::size_t i = 1; i < values.size(); ++i) {
        flag = append_flag(flag, values[i]);
    }

    return flag;
}


int main(int argc, const char* argv[]) {
    auto result = make_flag(Axis::X, Axis::Y, Axis::Z);
    auto value  = static_cast<std::size_t>(result);
    std::cout << value << " (" << std::bitset<16>(value) << ")" << std::endl;
    return 0;
}

Given that you just have 3 axes and a limited amount of combinations, I'd suggest just defining them all.

enum class Axis : std::uint_fast16_t {
    X   = 0,
    Y   = 1,
    Z   = 2,
    XX  = 3,
    YX  = 4,
    ZX  = 5,
    XY  = 6,
    YY  = 7,
    ZY  = 8,
    XZ  = 9,
    YZ  = 10,
    ZZ  = 11,
    XXX = 12,
    YXX = 13,
    ZXX = 14,
    XYX = 15,
    YYX = 16,
    ZYX = 17,
    XZX = 18,
    YZX = 19,
    ZZX = 20,
    XXY = 21,
    YXY = 22,
    ZXY = 23,
    XYY = 24,
    YYY = 25,
    ZYY = 26,
    XZY = 27,
    YZY = 28,
    ZZY = 29,
    XXZ = 30,
    YXZ = 31,
    ZXZ = 32,
    XYZ = 33,
    YYZ = 34,
    ZYZ = 35,
    XZZ = 36,
    YZZ = 37,
    ZZZ = 38,
};

If you want to do it programmatically, what you can do is to make the flag by shifting the value by 2 every time you add a new flag, as each value is represented by 2 bits.

#include <type_traits>
#include <array>
#include <iostream>
#include <bitset>


enum class Axis : std::uint_fast16_t {
    X = 0b01,
    Y = 0b10,
    Z = 0b11,
};


Axis append_flag(Axis current, Axis to_append) {
    std::uint_fast16_t flag = static_cast<std::uint_fast16_t>(current);
    flag = (flag << 2) | static_cast<std::uint_fast16_t>(to_append);
    return static_cast<Axis>(flag);
}


template <class ... T>
Axis make_flag(T ... axes) {
    std::array values = { axes... };
    auto flag = values[0];
    for (std::size_t i = 1; i < values.size(); ++i) {
        flag = append_flag(flag, values[i]);
    }

    return flag;
}


int main(int argc, const char* argv[]) {
    auto result = make_flag(Axis::X, Axis::Y, Axis::Z);
    auto value  = static_cast<std::size_t>(result);
    std::cout << value << " (" << std::bitset<16>(value) << ")" << std::endl;
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文