io — C ++ Перегрузка операторов I / 0: преодоление неоднозначности в прошлом

Я нахожусь в процессе работы над классом, и у меня есть 3 массива в моем классе, где все они представляют одни и те же данные, но в другом формате. У меня перегрузка << оператор, который объявлен за пределами моего класса, который использует const-ссылку на него, а не как друга этого класса.

SomeClass {
public:
// Nameless Union - All 3 Arrays Are of The Same Exact Data Type
// And All 3 Arrays Have The Same Exact Size. This Nameless Union
// Uses The Same Memory Address For All 3 Arrays And Their Elements.
// So An Element Is Changed By One Array Type, It Is Expected And
// Accepted For It To Change The Others. This Is Not 3 Different
// Arrays, This Is Still 1 Array Of Size 256, Just Different
// Representations Or Different Ways To Access Them.
union {
int m_256[256];
int m_16[16][16];
int m_4[4][4][4][4];
};

SomeClass() { std::fill( std::begin( m_256 ), std::end( m_256 ), 0 ); }

}; // SomeClass

std::ostream& operator<<( std::ostream& out, const SomeClass& c ) {
out << std::endl;

for ( unsigned box = 0; box < 4; box++ ) {
for ( unsigned slice = 0; slice < 4; slice++ ) {
for ( unsigned row = 0; row < 4; row++ ) {
for ( unsigned col = 0; col < 4; col++ ) {
out << "(" << box << "," << slice << "," << row << "," << col << ") = "<< c.m_4[box][slice][row][col] << std::endl;
}
}
}
}
return out;
} // operator<<

Это то, что у меня сейчас есть. То, что я хотел бы сделать, это также использовать operator<< с этим классом, но чтобы иметь возможность различать способ отображения одних и тех же данных в другом формате.

Я знаю, что вы не можете сделать это: добавив 2-й

std::ostream& operator<<( std::ostream& out, const SomeClass& c ) {
out << std::endl;
for ( unsigned i = 0; i < 16; i++ ) {
for ( unsigned j = 0; j < 16; j++ ) {
out << "(" << i << "," << j << ") = " << c.m_16[i][j] << std::endl;
}
}
return out;
} // operator<<

И третий

std::ostream& operator<<( std::ostream& out, const SomeClass& c ) {
out << std::endl;
for ( unsigned u = 0; u < 256; u++ ) {
out << u << " = " << m_256[u] << std::endl;
}
return out;
} // operator<<

В связи с тем, что это неоднозначно. Тем не менее, я хотел бы иметь функциональность для отображения в любом из 3 различных форматов.

Есть ли какие-либо рабочие раунды или решения этой проблемы? Я хотел бы иметь возможность просто отправить объект класса оператору потока, и эти типы операторов не могут принимать дополнительные параметры, поскольку они являются бинарными операторами, а не функцией.

0

Решение

Вы можете просто использовать класс адаптера для записи вывода. Вы можете передать спецификатор формата в конструктор или дифференцировать по типу. Например (дифференциация по типу):

struct SomeClassAs256 {
SomeClass const& x_;

explicit(SomeClass const& x) : x_(x) {}
};

И тогда есть оператор<< реализация:

ostream& operator<<(ostream& os, SomeClassAs256 const& x) {
...
return os;
}

И тогда вы используете это:

SomeClass x;
...
cout << SomeClassAs256(x) << endl;
4

Другие решения

Вы не можете сделать это, по крайней мере, не так просто.

Это оставляет вам два варианта: использовать две функции, которые создают строку и возвращает ее, или создавать структуру потокового манипулятора.

Создать набор функций форматирования, который возвращает строку, которая затем используется для вывода, просто с помощью std::ostringstream:

std::string format1(SomeClass const& c)
{
std::ostringstream os;
os << whatever you want ...
return os.str();
}

Создание структур манипуляторов немного сложнее, но также может быть более гибким и мощным:

class format1
{
public:
format1(SomeClass const& c)
: c_(c)
{}

friend std::ostream& operator<<(std::ostream& os,
format1 const& fmt)
{
os << some formated output here using `fmt.c_`...;
return os;
}

private:
SomeClass const& c_;
};

В обоих случаях вы можете использовать его одинаково:

SomeClass c(...);
std::cout << format1(c) << '\n';
2

Вы можете сделать это, возвращая прокси (для обеспечения адаптации) из вашего класса, используя make-функции и используя:
оператор << (ostream, SomeClass :: Proxy) в качестве оператора вывода. Я поработаю над примером кода.

Таким образом, вам не нужно выставлять внутренности вашего класса тоже. Ничего плохого в том, чтобы сделать оператора << друзья …

Пример:

#include <iostream>
class SomeClass {
union {
int m_256[256];
int m_16[16][16];
int m_4[4][4][4][4];
};
public:

SomeClass() { std::fill( std::begin( m_256 ), std::end( m_256 ), 0 ); }

struct x256
{
const SomeClass& c_;
explicit x256(const SomeClass& c): c_(c)
{
}
};
struct x16
{
const SomeClass& c_;
explicit x16(const SomeClass& c): c_(c)
{
}
};

struct x4
{
const SomeClass& c_;
explicit x4(const SomeClass& c): c_(c)
{
}
};

x256 output265() const
{
return x256(*this);
}

x16 output16() const
{
return x16(*this);
}

x4 output4() const
{
return x4(*this);
}

friend std::ostream& operator<<( std::ostream& out, const SomeClass::x256& c ) {
out << std::endl;
for ( unsigned u = 0; u < 256; u++ ) {
out << u << " = " << c.c_.m_256[u] << std::endl;
}
return out;
} // operator<<
friend std::ostream& operator<<( std::ostream& out, const SomeClass::x16& c ) {
//...
return out;
} // operator<<
friend std::ostream& operator<<( std::ostream& out, const SomeClass::x4& c ) {
//...
return out;
} // operator<<
}; // SomeClass

void testSomeClass()
{
SomeClass someClass;

std::cout << someClass.output265() << someClass.output16() << someClass.output4() << std::endl;
}
1

Увидев несколько хороших ответов и учитывая, что ostream объект и operator<< не может знать, какой тип использовать, и, полагая, что пользователь решит отобразить информацию для своих нужд, я пошел другим путем; однако решение, которое я нашел, которое работает для моих текущих потребностей, было поддержано и вдохновлено всеми теми, кто оставил отличные ответы на эту проблему.

Направление, которое я выбрал, было таким; Я добавил enum в мой класс непосредственно с 3 типами. Я добавил публичную функцию, которая выводит строку и принимает enum введите в качестве параметра. Я добавил ostream operator<< в мой класс и параметр, который он принимает, является typename на мои занятия enum, Я использую функцию out, чтобы разветвлять мои 3 различных способа отображения информации. Так что теперь в другом разделе кода, который использует этот объект, я могу передать экземпляр, вызывающий функцию out, которая возвращает строку, передавая требуемый тип. Мой класс теперь выглядит так:

class SomeClass {
public:
enum OutputType { x256, x16, x4 };

union {
int m_256[256];
int m_16[16][16];
int m_4[4][4][4][4];
};

std::string out( OutputType type ) const;

std::ostream& operator<<( typename SomeClass::OutputType type );

}; // SomeClassstd::ostream& SomeClass::operator<<( typename SomeClass::OutputType type ) {
return std::ostream << out(type );
} // operator<<

std::string SomeClass::out( OutputType type ) const {
std::ostringstream out;
out << std::endl;

switch( type ) {
case: x256: {
// Print Format Here
break;
}
case x16: {
// Print Format Here
break;
}
case x4: {
// Print Format Here
break;
}
default: {
// Error Message
return out.str();
}
}
return out.str();
} // out

Я не знаю, связано ли это с моим классом в моем проекте, будучи template или как operator<< реализовано, но я должен был использовать typename с в объявлении / определении функции для его работы, так что это выглядит в моем коде, за исключением имени класса.

template< class T>
std::ostringstream& SomeClass<T>::operator<<( typename SomeClass<T>::Type type ) {
// Code Here
}

Я ценю всю помощь и предложения, которые вы все предложили, и я принимаю тот совет, который был дан всем сердцем, спасибо всем.

редактировать

Теперь, если я хочу сделать это немного проще для пользователя: я мог бы переместить свою функцию out в приватный раздел; Напишите 3 обертки или напечатайте функции, которые не принимают никаких параметров, но они устанавливают переменную в закрытый метод.

1

Добавьте некоторый способ, например, член к вашему классу, чтобы решить выходной формат:

public:
enum OutputStyle
{
M_256,
M_16,
M_4,
};
OutputStyle style() const {return style_;}

private:
mutable OutputStyle style_ = M_256;

Добавьте некоторый способ, например, оператор вызова функции, чтобы установить это:

public:
SomeClass const& operator()(OutputStyle s) const
{
style_ = s;
return *this;
}

Сделать << оператор, чтобы рассмотреть это:

std::ostream& operator<<( std::ostream& out, const SomeClass& c )
{
switch( c.style() )
{
default:
assert(!"defective operator <<");
case SomeClass::M_256:
// ... output like M_256 here
break;
case SomeClass::M_16:
// ... output like M_16 here
break;
case SomeClass::M_4:
// ... output like M_4 here
break;
}
}

Затем вы можете изменить его до или во время вывода:

    SomeClass x; // <- has style M_256

x(SomeClass::M_16);

std::cout << "current:" << x << std::endl
<< "with M_4:" << x(SomeClass::M_4) << std::endl;
1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector