C ++: пользовательский тип данных - проблемы с типизацией и объединением - PullRequest
1 голос
/ 29 сентября 2010

Я пытаюсь создать новый пользовательский тип данных, который будет вести себя как все другие примитивные типы.В частности, этот тип данных выглядит как дробь с фиксированной точкой.Я создал класс для представления этого типа данных, который называется «класс FixedPoint», и в нем есть способы трансляции типов из «FixedPoint» в «int», «double» или «unsigned int» и т. Д. Это нормально.

А что если я хочу разыграть с "int" to "FixedPoint"?Первоначально мое решение состояло в том, чтобы иметь конструктор:

FixedPoint(int i) { /* some conversion from 'int' to 'FixedPoint' in here */ }

Это работает ... но вы не можете поместить его в объединение следующим образом:

 union {
   FixedPoint p;
 };

Это сломается, потому что "FixedPoint«не имеет неявного тривиального конструктора (мы только что определили конструктор« FixedPoint (int i) »).

Подводя итог, можно сказать, что вся проблема в том, что« мы хотим cast from some type T to type FixedPoint without explicitly defining a constructor, чтобы мы могли использовать наш типFixedPoint in the union ".

Я думаю, что решение, но не может найти никаких доказательств в Интернете: определить перегруженный глобальный оператор Typecast для преобразования из" int "в" FixedPoint ".

Есть ли способ сделать это без использования конструкторов классов?Я хотел бы иметь возможность использовать этот класс в союзе.Что я пробовал (в глобальном масштабе):

operator (FixedPoint f, int a) { ... } //compiler complains about this is not a method or non-static.

И небольшой пример того, как профсоюзы не любят конструкторов (им нравится POD)

class bob
{
  public:
    bob(int a) { m_num = a; }
  private:
    int m_num;
};
void duck()
{
  union 
  {
    bob a;
  };
}

Эта ошибка замечена вVisual Studio это:

error C2620: member 'duck::<unnamed-tag>::a' of union 'duck::<unnamed-tag>' has user-defined constructor or non-trivial default constructor

Есть идеи?Спасибо

Ответы [ 3 ]

0 голосов
/ 29 сентября 2010

Разве вы не можете просто добавить конструктор по умолчанию, который позволит ему быть частью объединения.

Например:

class bob
{
  public:
    bob(int a=0) { m_num = a; }
  private:
    int m_num;
};
void duck()
{
  union 
  {
    bob a;
  };
}

Если задать значение по умолчанию a=0, его можно будет объединить. Я сам не пробовал, хотя.

0 голосов
/ 29 сентября 2010

Мне трудно понять, для чего вы пытаетесь использовать это.Кажется вонючим постоянно требовать, чтобы sizeof(FixedPoint) == sizeof(int) и, при условии, что есть и другие скрытые ошибки, такие как endianness.Может быть, я должен немного сделать резервную копию, профсоюзы только «преобразуют» значение из одного типа в другой, так как оно занимает кусок памяти и ссылается на него как другой тип.т. е.

union BadConverter
{
    int integer;
    double fraction;
};

BadConverter.fraction = 100.0/33.0;
BadConverter.integer = ?;

Я почти уверен, что целое число не будет равно 3, оно будет равно какому-либо фрагменту памяти двойного числа, которым целые байты делятся с ним.

Союзы, похоже, не очень подходят для такого рода вещей.Я бы подумал просто определить кучу операторов присваивания из всех примитивных типов.т.е.

class FixedPoint
{
    FixedPoint& operator=(int value);
    FixedPoint& operator=(double value);
    ..etc..
    //Maybe something like this?
    template<typename T>
    FixedPoint& operator=(const T& value)
    {
        value = boost::lexical_cast<int>(value);
        return *this;
    }
}
0 голосов
/ 29 сентября 2010

Пользовательские операторы преобразования должны быть членами преобразуемого класса из . Нетривиальный конструктор не требуется.

РЕДАКТИРОВАТЬ: я переделал пример для использования union, так как это то, о чем вы спрашивали.

РЕДАКТИРОВАТЬ2: см. Ниже, если вы пытаетесь пойти другим путем (строительство) и не хотите конструкторов.

#include <string>
#include <sstream>
using namespace std;

class FixedPoint
{
public:
    operator std::string() const
    {
        stringstream ss;
        ss << x_ << ", " << y_;
        return ss.str();
    }
    int x_, y_;
};

union Items
{
    FixedPoint point_;
    int val_;
};

int main()
{
    Items i;
    i.point_.x_ = 42;
    i.point_.y_ = 84;
    string s = i.point_;
}

Если вы пытаетесь пойти другим путем - например, с int до FixedPoint в моем примере - тогда обычный способ сделать это - использовать конструктор преобразования. Учитывая, что вам не нужен нетривиальный конструктор, вам придется прибегнуть к функции преобразования.

FixedPoint make_fixed_point(int x, int y)
{
    FixedPoint ret;
    ret.x_ = x;
    ret.y_ = y;
    return ret;
}

union Items
{
    FixedPoint point_;
    int val_;
};


int main()
{
    Items i;
    i.point_ = make_fixed_point(111,222);
}
...