是否有一种方法可以通过`typedef`定义基本类型的特征并强制转换以进行重定义?

时间:2020-02-22 21:50:15

标签: c++ casting operators typedef

我编写了一对转换器函数,用于在弧度角和二进制角(又名BAMS)的浮点表示形式之间进行转换:

// Binary angles that maps into 360 degree circle
typedef uint8_t  binang8_t;
typedef uint16_t binang16_t;
typedef uint32_t binang32_t;
typedef uint64_t binang64_t;

// Convert from radians to BAMS
template<typename A, typename T> A to_binang(T val);

// Convert from radians or BAMS
template<typename T, typename A> T to_rads(A val);

主要问题是我创建的is_binangle特性在转换器内部使用,无法防止使用无符号整数代替新类型。 我知道,我可以将这些新类型定义为结构,它将解决此问题 ,但是我有理由不将其声明为class或{{1 }}(以避免重新定义算术运算符,并与旧的C有效负载标头保持兼容)。有没有技巧可以使其与使用struct定义的类型一起使用? 这是我尝试实现的特征:

typedef

理想情况下,我希望为这些类型定义自定义强制类型转换,以便可以通过以下方式进行转换:

template<typename T> struct is_binangle {
    static const bool value = false;
};

template<> struct is_binangle<binang8_t> {
    static const bool value = true;
};

template<> struct is_binangle<binang16_t> {
    static const bool value = true;
};

...

我非常怀疑除非这些二进制角为double rangle = M_PI/6; binang16_t bang = binang16_t(rangle); bang += bang; double another_rangle = double(another_bang); / classes,否则是不可能的。是吗?

2 个答案:

答案 0 :(得分:0)

您可以将enum用于此目的:

#include <cstdint>
#include <type_traits>

enum binang8_t : uint8_t {};

template <typename T>
struct is_binang : std::false_type {};

template <>
struct is_binang<binang8_t> : std::true_type {};

// static_assert(is_binang<uint8_t>::value);  --> This fails
static_assert(is_binang<binang8_t>::value);

extern "C" void some_c_function(uint8_t);

int main() {
    binang8_t val = static_cast<binang8_t>(0);
    some_c_function(val);
    return 0;
}

Compiler explorer

之所以可行,是因为未作用域的枚举具有唯一的类型(与它们的基础整数类型不同),并且它们可以隐式转换为整数(因此您可以将它们传递给接受整数的C函数,而无需强制转换)。

我承认这并不完美,因为如果您进行算术运算,则必须将结果强制回退到binang8_t,并且它不适用于浮点数。

答案 1 :(得分:0)

答案是一半(模板类替换了这4个typedef-s),但是还有另一个问题-教科书成员模板函数实现失败)

希望我能够说服C语言程序员使用C ++数组

struct blah {
  uint16_t value;
};

可以看作是uint16_t值的数组,我确实尝试了宣告class的艰辛:

template<typename UnsignedInt,
        std::enable_if_t<std::is_unsigned<UnsignedInt>::value, int> = 0>
class binangle {
    UnsignedInt value;
public:
    binangle(UnsignedInt v) : value(v) {}

    template<typename F>
    binangle(F v) { set_from_radians<F>(v); }

    template<typename F>
    void set_from_radians(F rad);

    template<typename F>
    void set_from_degrees(F rad);

    template<typename F>
    F to_radians(int start_deg = 0) const;

    template<typename F>
    F to_degrees(int start_deg = 0) const;

    template<typename F> operator F() const;

    explicit operator UnsignedInt() const { return value; }
};

...直到我开始执行那些模板成员函数时,一切都花了-当编译器看到

template<typename UnsignedInt>
template<typename F>
void binangle<UnsignedInt>::set_from_radians(F rad) {
...

它抛出

...
   /home/sipan/src/vgit/signals/tests/../include/binangles_impl.hpp:23:51: error: invalid use of incomplete type ‘class signals::binangle<UnsignedInt>’
   23 | void binangle<UnsignedInt>::set_from_radians(F rad) {
      |