Есть ли способ определить черты и операторы приведения для переопределенных типов через typedef, basi c? - PullRequest
0 голосов
/ 23 февраля 2020

Я написал пару функций преобразователя для преобразования между представлением углов с плавающей точкой в ​​радианах и двоичными углами (он же 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 или struct (чтобы избежать переопределения арифметика c операторов и совместимость со старыми C заголовками полезной нагрузки). Есть ли хитрость, чтобы заставить его работать с типами, определенными с помощью 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 / structures. Это правильно?

Ответы [ 2 ]

0 голосов
/ 23 февраля 2020

Это наполовину ответ (класс шаблона заменяет эти 4 typedef -ы), но есть еще одна проблема - сбой реализации функции шаблона члена учебника)

В надежде, что я смогу Чтобы убедить 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) {
      |
0 голосов
/ 23 февраля 2020

Вы можете использовать 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;
}

( Проводник компилятора )

Это работает, потому что перечисления с незаданной областью имеют уникальные типы (не то же самое с их базовым целочисленным типом), и они неявно преобразуются в целые числа (так что вы можете передать их функции C, которая принимает целые числа без приведения).

Это не идеально, я признаю, как вы должны приведите результат обратно к binang8_t, если вы выполняете арифметические операции c, и он не работает для чисел с плавающей запятой.

...