2013-06-21 5 views
1

Я хотел бы найти/реализовать совместимый поток C++ (надеюсь, stl), который поддерживает несколько точек записи. То, что я имею в виду с несколькими точками письма, легко объяснить в следующем примере. Предположим, что вы хотите сгенерировать файл исходного кода, скажем, на языке Java. Когда вы дойдете до точки, где вы хотите, чтобы написать строку кода, которые имеют зависимость от конкретного пакета - вы можете написать:C++ Несколько точек точек записи

stream << "import java.applet.*;"; 

stream << "public class MyApplet extends Applet {"; 
stream << "..."; 
stream << "}"; 

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

Я знаю, что я мог бы решить эту проблему другими способами. Я думаю, что будет здорово, если я смогу его решить с помощью некоторого stl-потока.

Является ли повышающий тройник с некоторой фильтрацией чего-то, что может работать?

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

stream << Import("java.applet.*); 

где импорт является классом, соответственно сериализован.

Как вы себя чувствуете - это то, что может стоить усилий?

+0

Прежде всего, я надеюсь, вы поймете, что для того, чтобы сделать это правильно, вам в основном придется разбирать язык. Я также надеюсь, что вы понимаете, что не можете просто игнорировать новые строки, например, ваши примеры.Что происходит, когда кто-то использует 'stream <<" \ ""; '? – Wug

+0

Во-вторых, я хотел бы спросить, что именно вы делаете, написав программу на C++, которая генерирует java-программу. Существуют определенные проблемы с эксплуатацией, которые становятся возможными, когда вы даете программе возможность писать другие программы на основе пользовательского ввода. – Wug

+0

Это был просто пример объяснения парадигмы потока множественных пишущих точек - я не генерирую Java с помощью C++ ... но это именно то, что такое проект, как буферы протокола google .. – gsf

ответ

0

В порядке возрастания сложности:

Во-первых, просто использовать различные переменные для каждого из мест, где вы можете захотеть написать. Затем соедините данные, которые вы поместите в каждый поток вместе, когда закончите.

В качестве второго уровня сложности храните std::tuple< std::ofstream, std::ofstream, std::ofstream > straems, затем используйте std::get<0>(streams), чтобы получить первый. Если вам нужны имена, используйте enum { first_stream, second_stream_name, third_stream_name } и передайте это значение std::get.

Для наиболее сложного ответа ... ну, это беспорядок.

Первый шаблон метапрограммированием шаблонный:

template<typename T, typename Tags, typename=void> 
struct index_of {}; 
template<typename T, template<typename...>class Pack, typename Tag0, typename... Tags> 
struct index_of<T, Pack<Tag0, Tags...>, typename std::enable_if< std::is_same<T, Tag0>::value >::type > 
: std::integral_constant< int, 0 > {}; 
template<typename T, template<typename...>class Pack, typename Tag0, typename... Tags> 
struct index_of<T, Pack<Tag0, Tags...>, typename std::enable_if< !std::is_same<T, Tag0>::value >::type > 
: std::integral_constant< int, index_of<T, Pack<Tags...> >::value + 1 > {}; 

template<typename Src, template<typename...>class Pack> 
struct copy_types {}; 

template<template<typename...>class Lhs, typename... Ts, template<typename...>class Target> 
struct copy_types< Lhs<Ts...>, Target > { 
    typedef Target<Ts...> type; 
}; 
template<typename Src, template<typename...>class Pack> 
using CopyTypes = typename copy_types<Src, Pack>::type; 

template<typename Pack, typename T> 
struct append {}; 
template<template<typename...>class Pack, typename... Ts, typename T> 
struct append<Pack<Ts...>, T> { 
    typedef Pack<Ts..., T> type; 
}; 
template<typename Pack, typename T> 
struct Append = typename append<Pack, T>::type; 

template<template<typename...>class Pack, typename T, std::size_t N> 
struct repeat { 
    typedef Append< repeat< Pack, T, N-1 >::type, T > type; 
}; 
template<template<typename...>class Pack, typename T> 
struct repeat< Pack, T, 0 > { 
    typedef Pack<> type; 
}; 
template<template<typename...>class Pack, typename T, std::size_t N> 
using Repeat = typename repeat<Pack, T, N>::type; 

Теперь, потому что это весело, помеченный кортеж:

template<typename T, typename Tags> 
struct type_based_map; 

template<typename T, template<typename...>class Pack, typename... Tags> 
struct type_based_map< T, Pack<Tags...> > { 
    Repeat< std::tuple, T, sizeof...(Tags) > data; 
    template<typename Tag> 
    T& get() { 
    return std::get< index_of< Tag, std::tuple<Tags...> >::value >(data); 
    } 
    template<typename Tag> 
    T& get() const { 
    return std::get< index_of< Tag, std::tuple<Tags...> >::value >(data); 
    } 
    template<typename... Args, typename=typename std::enable_if< sizeof...(Args) == sizeof...(Tags) >::type > 
    explicit type_based_map(Args&&... args):data(std::forward<Args>(args)...) {} 
    type_based_map(type_based_map&&) = default; 
    type_based_map(type_based_map const&) = default; 
    type_based_map(type_based_map&) = default; 
}; 

Теперь, вплоть до мяса и картофеля. Поли-поток:

template<typename Tag, typename U> 
struct TaggedData { 
    U&& data; 
    explicit TaggedData(U&& u):data(std::forward<U>(u)) {} 
    TaggedData(TaggedData &&) = default; 
    TaggedData(TaggedData const&) = default; 
    TaggedData(TaggedData &) = default; 
}; 
template<typename Tag> 
struct DataTagger { 
    template<typename U> 
    TaggedData<U> operator()(U&& u) const { 
    return {std::forward<U>(u)}; 
    } 
}; 

template<typename base_stream, typename Tags> 
struct tagged_stream: type_based_map< base_stream, Tags > 
{ 
    using type_based_map< base_stream, Tags >::type_based_map< base_stream, Tags >; 
}; 
template<typename base_stream, typename Tags, typename Tag, typename U> 
auto operator<<(tagged_stream<base_stream, Tags>& stream, TaggedData<Tag, U> data) 
    ->declval(stream.get<Tag>() << std::forward<U>(data.u)) 
    { return (stream.get<Tag>() << std::forward<U>(data.u)); } 

, которые, как только ошибки устранены, дает следующий синтаксис:

struct bob {}; 
struct harry {}; 
struct alice {}; 
static DataTagger<bob> Bob; 
static DataTagger<harry> Harry; 
static DataTagger<alice> Alice; 

typedef tagged_stream< std::ofstream, std::tuple<bob, harry, alice> > multi_out; 

multi_out os; 
os.get<bob>().open("bob.txt"); 
os.get<harry>().open("harry.txt"); 
os.get<alice>().open("alice.txt"); 
os << Bob(7) << " is seven in Bob\n"; 
os << Harry("hello") << " in Harry\n"; 
os << Alice(3.14) << " is baked by Alice\n"; 

, которые могут или не могут быть то, что вы ищете.

Это далеко не отлажено и, вероятно, пока не компилируется.

Честно? Просто введите переменную для каждого потока. В любом случае вы захотите объединить их вручную вручную в конце.