Как бы я использовал операторы >> и << для двоичных данных в C ++? - PullRequest
4 голосов
/ 24 ноября 2008

Есть ли способ использовать эти операторы для ввода и вывода двоичных данных? Причина, по которой я хочу это сделать, заключается в том, что он делает код читабельным. Пример: infile >> filedecrypter >> metadataparser >> audiodecoder >> эффект >> soundplayer;

Ответы [ 4 ]

3 голосов
/ 24 ноября 2008

Действительно, это можно сделать, если библиотека или ваш код обеспечивает перегрузки для operator<< и operator>> для его работы. Простой пример того, как можно это сделать:

class transformer {
    public:
    virtual std::iostream& transform(std::iostream&) = 0;
};

class noise : public transformer {
    public:
    virtual std::iostream& transform(std::iostream&) {
         /* extract, change and put into again */
    }
};


class echo : public transformer {
    public:
    virtual std::iostream& transform(std::iostream&) {
         /* extract, change and put into again */
    }
};

std::iostream& operator>>(std::iostream& io, transformer& ts) {
    return ts.transform(io);
}

int main() {
    std::stringstream data;
    std::ifstream file("sound.wav");

    noise n; echo e;

    data << file.rdbuf();
    data >> n >> e;
    /* pipelined data now ready to be played back */
}

Проблема с использованием чистого std::istream заключается в том, что вы читаете, но тогда у вас не будет способа вернуть преобразованные данные для следующего шага в конвейере. Таким образом, я использую std::iostream здесь. Этот подход не кажется эффективным, так как каждый оператор >> вызов будет извлекать все данные и помещать их снова.

Чтобы иметь более эффективный способ потоковой передачи, это должно было бы создать expression template. Это означает, что при вызове operator>> преобразование еще не выполнено, но вы возвращаете типы выражений, которые будут записывать цепочку операций в своем типе:

typedef transform< echo< noise< istream > > > pipeline;
std::ifstream file("file.wav");
pipeline pipe(file);
int byte = pipe.get();

будет примером такого типа. Структура трубопроводов декодируется в сам тип. Поэтому в конвейере больше не требуется никаких виртуальных функций. Он не построен по требованию, но использует typedef здесь, чтобы показать принцип. Программирование такой системы не просто. Поэтому вам, вероятно, следует изучить существующие системы, такие как Boost.Iostreams (см. Ниже). Чтобы дать вам представление о том, как это будет выглядеть, вот пример, который я только что написал для вас :):

#include <iostream>

template<typename T>
struct transformer {
    int get() {
        return static_cast<T*>(this)->read();
    }
};

struct echot {
    template<typename Chain>
    struct chain : transformer< chain<Chain> > {
        Chain c;

        int read() {
            return c.get() + 1;
        }

        chain(Chain const& c):c(c) { }
    };
} echo;

struct noiset {
    template<typename Chain>
    struct chain : transformer< chain<Chain> > {
        Chain c;

        int read() {
            return c.get() * 2;
        }

        chain(Chain c):c(c) { }
    };
} noise;


template<typename T>
typename T::template chain<std::istream&> operator>>(std::istream& is, T) {
    return typename T::template chain<std::istream&>(is);
}

template<typename T, typename U>
typename U::template chain<T> operator>>(T t, U u) {
    return typename U::template chain<T>(t);
}

int main() {
    std::cout << (std::cin >> echo >> noise).get() << std::endl;
}

Ввод 0 дает здесь код 48 ASCII, который добавляется 1 и умножается на 2, давая значение 98, которое также в конечном итоге выводится. Я думаю, что вы согласны, что это не какой-то код, который автор хотел бы написать. Так что, возможно, посмотрите на повышение.

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

2 голосов
/ 24 ноября 2008

Просто чтобы прояснить, вы собираетесь дублировать семантику iostreams? Потому что, похоже, вы предлагаете что-то другое. В приведенном вами примере:

infile >> filedecrypter >> metadataparser >> audiodecoder >> effects >> soundplayer;

В iostreams смысл здесь состоит в том, чтобы читать из infile в filedecrypter до тех пор, пока вы не доберетесь до пробела, а затем из infile в metadataparser до большего количества пробелов и т. Д.

Похоже, вы предлагаете что-то другое, когда metadataparser читает из filedecrypter, audiodecoder из metadataparser и т. Д. В этом случае я думаю, что ответ на ваш вопрос нужно немного уточнить.

Можете ли вы использовать оператор >> для выражения этой конструкции? Вероятно, да .

Можете ли вы использовать iostreams для этого? Вероятно, нет .

Я предлагаю вам уточнить, что это значит, когда вы говорите A >> B. Возможно, сначала выразите это как обычные методы, а не перегрузки операторов, и это может прояснить вопрос.

2 голосов
/ 24 ноября 2008

Нет необходимости использовать потоки для перемещения данных. Вы можете создать свои собственные классы, чтобы сделать это. Это показывает пример. Очевидно, что классы Decrypt и MetaDataParser могут быть абстрактными базовыми классами с виртуальными функциями, позволяющими объединять различные функции.

#include <iostream>                                                         
#include <istream>                                                          
using namespace std;                                                        

class Data2                                                                 
{                                                                           
};                                                                          

class Data3                                                                 
{                                                                           
};                                                                          

class Decrypt                                                               
{                                                                         
};                                                                          

class MetaDataParser                                                        
{                                                                           
};                                                                          

Data2& operator>>(istream& in, Decrypt& decrypt)                            
{                                                                           
  return *new Data2;                                                        
}                                                                           

Data3& operator>>(Data2& d2, MetaDataParser& mdp)                           
{                                                                           
  return *new Data3;                                                        
}                                                                           

int main()                                                                  
{                                                                           
  Decrypt decrypt;                                                          
  MetaDataParser mdp;                                                       

  cin >> decrypt >> mdp;                                                    
}                                                                           
2 голосов
/ 24 ноября 2008

Конечно, это можно сделать. Просто определите свой собственный оператор >> и оператор <<, чтобы они делали "правильные вещи" ... </p>

Я хотел бы сделать так, чтобы у меня были методы в классе, такие как toStream (ostream & os) и fromStream (istream &), а затем определить

istream& operator>> (istream& is, T& t)
{
     t.fromStream(is);
     return t;
}

ostream& operator<< (ostream& os, const T& t)
{
     t.toStream(os);
     return t;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...