Реализация алгоритма RLE в стиле метапрограммирования C++

Я реализовал простой рекурсивный алгоритм для RLE (кодирование длины цикла).

Код:

#include <iostream>
using namespace std;

template <size_t N>
struct RLE {
    static size_t cnt;

    static void Compress(char const p[]) {                
        // Check current char with next char. If they are not same then print the current character and its count. Then reset the counter to 0 for next itetation.
        if (!(*p == *(p + 1))) {
            cout << cnt << *p;
            cnt = 0;
        }
        // Call the function again with new character
        RLE<N - 1>::Compress(p + 1);
    }
};

template <size_t N>
size_t RLE<N>::cnt = 1 + RLE<N - 1>::cnt;

template <>
struct RLE<0> {
    static size_t cnt;
    static void Compress(char const[]) {
    }
};;

//template<>  // On uncomenting this like why do I get a error "extraneous template<>, in declaration of variable cnt."
size_t RLE<0>::cnt = 0;

int main(void) {
    char const str[]{"mmatsss"};

    // -1 since sizeof includes terminating null char.
    RLE<sizeof(str) - 1>::Compress(str);
}

Для ввода типа «mmatsss» ожидаемый результат — «2m1a1t3s», но я получаю «1m1a1t1s», т. е. код печатает только первый символ группы. Я не могу понять ошибку в коде. Может кто-нибудь, пожалуйста, взгляните на это и помогите мне понять, что я делаю неправильно здесь.

Этот код создает 6m5a4t1 с использованием gcc. Пожалуйста, убедитесь, что у вас есть точный код, точный вывод, и сообщите нам свой компилятор. Требуется минимальный воспроизводимый пример.

Yakk - Adam Nevraumont 04.03.2019 03:02

@Yakk - Adam Nevrsumont Я скомпилировал код на мобильном компиляторе Cxxdroid и получил результат, о котором я упоминал в посте, но когда я попробовал с онлайн-компиляторами, я получил результат, о котором вы упомянули, возможно, мне нужно изменить свой компилятор. дополнительный вопрос, является ли отрицательный результат неполным, не поддающимся проверке и / или вопрос не соответствует стандартам StackOverflow

NeutronStar 04.03.2019 03:16

Я использовал c4droid. И прочитайте код, и он должен делать то, что говорит c4dtoid.

Yakk - Adam Nevraumont 04.03.2019 04:02

@Yakk-AdamNevraumont У меня на телефоне нет приложения C4Droid. Cxxdroid был бесплатным, поэтому я его использовал.

NeutronStar 04.03.2019 04:09
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
131
1

Ответы 1

I am unable to figure out the bug in the code, can someone please take a look at it, and help me to understand what am i doing wrong here.

Проблема в том, что вы инициализируете статический член cnt следующим образом

template <size_t N>
size_t RLE<N>::cnt = 1 + RLE<N - 1>::cnt;

size_t RLE<0>::cnt = 0;

поэтому вы получаете cnt == N, когда компилятор использует инициализированное значение RLE<N - 1>::cnt (случай g++), cnt == 1, когда N > 0, когда компилятор использует ноль для RLE<N - 1>::cnt (случай clang++).

Я не знаю, кто прав, но дело в том, что когда ты пишешь

        cout << cnt << *p;
        cnt = 0;

вы печатаете cnt в RLE<N> -- так что N или 1, в зависимости от случая -- и обнуляете cnt в RLE<N>.

Но когда вы обнуляете cnt в RLE<N>, cnt в RLE<N-1> остаются неизменными (так что N-1 или 1, в зависимости от случая).

Я не вижу много метапрограммирования в вашем коде, но мне кажется, что возможная коррекция установлена ​​​​все cnt на 1

template <size_t N>
size_t RLE<N>::cnt = 1;

size_t RLE<0>::cnt = 1;

и установите RNE<N-1>::cnt как cnt + 1 в Compress()

static void Compress(char const p[])
{                
    if (!(*p == *(p + 1)))
    {
        cout << cnt << *p;
        cnt = 0u;
    }

    RLE<N - 1>::cnt = cnt+1u;  <---  add this line

    RLE<N - 1>::Compress(p + 1);
}

Но, честно говоря, я предпочитаю ваш оригинальный (не метапрограммный) код.

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

NeutronStar 04.03.2019 11:27

Другие вопросы по теме