2016-11-12 3 views
1

Я хочу создать несколько родственников std::fscanf() (Я знаю, что это функция C). Итак, мой интерфейс что-то вроде этого:Как перебирать пакет вариативных шаблонов во время (псевдо?) Времени исполнения?

template <charT, char_traits, ...> 
std::size_t ts_scanf(is, format, opening_bracket, closing_bracket, args) 

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

Вот как C# версии работы:

"text blah blah blah {0} {1} {0}", arg1, arg2 

Таким образом, делает вывод типов arg1, arg2, а затем читает текст в месте, где {N} стоит в соответствующий аргумент.

Алгоритм того, что я хочу сделать:

1.Find открывающая скобка

2.Try для разбора Int, скажем N

3.Если удалось, получить Nth параметр из пакета, прочитайте его, используя is>>get<N>args.

4.Ел не удался, выполнить немые читать

5.Повторите от 1 до 4 до конца формата или пока поток не исчерпывает

Таким образом, при написании цикла я встретил проблему:

for (i = 0; i < length; i = format.find(i, opening_bracket)) 

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

Вопрос: Есть ли решение, в котором можно было бы расширить вариационный пакет в (псевдо) времени выполнения?

+0

Что такое 'open_bracket' и' clos_bracket'? Зачем тебе это надо ? 'fscanf' не имеет ничего подобного AFAIK. Псевдокод о том, как вы хотите, чтобы он работал, проделал бы долгий путь, объясняя, чем вкладывать его в слова. – Arunmu

+0

@Arunmu, спасибо, добавлено – Incomputable

+0

Если вы хотите сделать это действительно эффективно, тогда вам нужно использовать шаблоны выражений, чтобы сделать это во время самого компиляции (сопоставление). Это можно сделать, используя 'boost :: proto', хотя я признаю, что это не для слабонервных :). Другое решение, которое я знаю, является чисто исполняемым, поскольку вы собираетесь разбирать скобки только во время выполнения. Это потребует хранения аргументов в контейнере времени выполнения. – Arunmu

ответ

2
template<class=void, std::size_t...Is > 
auto indexer(std::index_sequence<Is...>){ 
    return [](auto&&f)->decltype(auto){ 
    return decltype(f)(f)(std::integral_constant<std::size_t, Is>{}...); 
    }; 
} 
template<std::size_t N> 
auto indexer(){ 
    return indexer(std::make_index_sequence<N>{}); 
} 
template<std::size_t N> 
void for_each(F&& f) { 
    indexer<N>()([&](auto...Is){ 
    using discard=int[]; 
    (void)discard{0,(void(
     f(Is) 
    ),0)...}; 
    }); 
} 

indexer дает вам неупакованные индексы.

for_each называет f с i значения времени компиляции для каждого i до N.

Это позволит вам перебирать целые числа во время компиляции. Для отображения чисел во время выполнения для компиляции:

template<std::size_t N, class F> 
void pick(std::size_t I, F&& f){ 
    for_each<N>([&](auto i){ 
    if (I==i) f(i); 
    }); 
} 

Это вызывает f с компиляцией версией времени I так долго, как это меньше, чем N.

template<class...Args> 
void read(std::string pattern, Args&...args){ 
    auto tied=std::tie(args...); 
    for (i = 0; i < length; i = format.find(i, opening_bracket)) 
    pick<sizeof...(args)>(i, [&](auto i){ 
     std::cin>>std::get<i>(tied); 
    }); 
    } 
} 

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

Код не скомпилирован; дизайн звучит, но есть, вероятно, типы. Индексатор можно найти с помощью google (я написал его на SO раньше). Я написал его как for_each напрямую, но я считаю, что версия одного пакета слишком полезна. Здесь мне понадобилась отдельная версия пакета. Выбор просто использует его.

Вот прыжок таблица версия выбрать:

template<std::size_t N, class F> 
void pick(std::size_t I, F&& f){ 
    indexer<N>()([&](auto...Is){ 
    using table_f=void(*)(&f); 
    const table_f table[]={ 
     +[](F&f){ f(decltype(Is){}); }... 
    }; 
    table[I](f); 
    }); 
} 

проверки границ не включены. Эта версия не требует for_each, но некоторые компиляторы ломаются, когда их спрашивают o есть лямбда с пакетом параметров, нерасширенным внутри оператора.

+1

Спасибо, Шаблон-Йода. –