Функция для подсчёта количества элементов

Доброго дня!Есть картинка, представленная в виде двумерного массива. Эта картинка играет роль маски в операции по обработке изображений.Если значение пикселя == 0, следовательно - элемент не учитывается, иначе, если > 0 - то учитывается. Возникает задача подсчитать элементы маски, которые > 0.Вот код
#include <conio.h>#include <iostream>using namespace std;typedef unsigned char BYTE;//Calculate number of elements, equals to specified valuetemplate< class T >int count( T *pSrc, int width, int height, int pitch, int step, T val ){    int count = 0;    for ( int y = 0; y < height; y++ )        for ( int x = 0; x < width; x++ )        {            T a = pSrc[y*pitch + x * step];            T b = val;            if ( a == b )                count++;        }    return count;}void main( ){    BYTE test[] = {    0, 0, 0, 0,                0, 255, 255, 0,                0, 1, 1, 1,                0, 0, 0, 0 };    #if 1 // the result must be 5, but actually, we get 3        std::cout << count<bool>( (bool*)test, 4, 4, 4, 1, true );    #else        std::cout << count<BYTE>( (BYTE*)test, 4, 4, 4, 1, 255 );    #endif    getch( );}
Казалось бы, ничего подозрительного, но выражение
T a = pSrc[y*pitch + x * step];T b = val;if ( a == b )    count++;
 . . . работает не так, как хотелось бы.Необходимо, чтобы функция была именно такой, как представлена, т.е., чтобы выполнялось поэлементное сравнение.Как видно из кода, указатель на BYTE преобразуется в указатель на bool, что и является причиной ошибки.Вот в этом и вопрос - как написать универсальную функцию, которая подсчитывает количество элементов с указанным значением ?Основное требование: если в неё подать массив типа BYTE, то она должна подсчитать количество ненулевых значений ( с шаблонным параметром - bool )
14 ответов

Я так понял, функция написана в предположении, что bool ~ 1 биту, это не так, размеры всех встроенных типов кратны char.  Чтобы анализировать битовое представление, нужно использовать арифметические операции % и /.


 (bool*)test
так ты приводишь указатель, 255 от этого не станет равным true, который в свою очередь равен 1(скорее всего)


в функции count, вместо переменной step, нужно использовать sizeof(T)а вместо 
T a = pSrc[y*pitch + x * step];
правильнее будет написать:
T a = pSrc[y*width + x];
Добавлено через 57 секундв общем параметры step и pitch являются лишними


так ты приводишь указатель, 255 от этого не станет равным true
Да что ж такое, так и не начал стандарт читать:
An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool. Azero value, null pointer value, or null member pointer value is converted to false any other value is converted to true.
ISO/IEC 14882:1998, 4.12.


Lazin
в общем параметры step и pitch являются лишними
Нет, параметр step требуется для обработки отдельного канала изображения (чтобы шагать через 3 байта).Вообще, вопрос у меня не в этом. Не смотрите на pitch и step. . .Ulysses4j
Я так понял, функция написана в предположении, что bool ~ 1 биту
нет, не было такого предположения. Я знаю, сколько занимает каждый тип данных.Если прогнать программу в отладчике, то он будет показывать "верные" значения. ( см. приложение).Тут причина в том, что если берем значение a по указателю
T a = pSrc[y*pitch + x * step];
то не происходит конверсии в тип bool. ( это и понятно ), происходит лишь интрерпретация куска памяти как bool.Операция == выполняется побитово. Из за этого и получается
    BYTE a = 255;    BYTE b = 1;    if ( *(bool*)&a == *(bool*)&b )        std::cout << "true";    else        std::cout << "false"; //попадём сюда    if ( (bool)a == (bool)b )        std::cout << "this will be ok";
А вообще, на 90 % уверен, что такая задача не решаема универсальным способом.  capture.JPG 157,82 Kb


Я так понял, функция написана в предположении, что bool ~ 1 биту, это не так, размеры всех встроенных типов кратны char.  Чтобы анализировать битовое представление, нужно использовать арифметические операции % и /. 
вообще-то указателя на бит не бывает  а что-бы анализировать битовое представление нужно использовать битовые операции >> << & | ~  


#include <iostream>int main(){    unsigned char test[] = {    0, 0, 0, 0,        0, 255, 255, 0,        0, 1, 1, 1,        0, 0, 0, 0 };     bool *test1 = (bool*)test;    for(int i = 0; i < sizeof(test); ++i)        std::cout << (test1[i] == true) << "\n";    std::cin.get();    return 0;} 
vs2008 выводятся 3 еденицы
can be
ни о чем Вам не говорит?Прежде чем чем то тыкать, проверяем   


ANTON_AL, на скриншоте вызов count или count?


Дело не в can be,  а в том что я перепутал преобразования (bool*)(·) и (bool)(·). Если вам не нравится, когда вам тыкают, прошу прощения, впредь буду более бережным к вашим чувствам.
вообще-то указателя на бит не бывает  
А где я сказал, что бывают указатели на бит? Я сказал, что смотря на функцию складывается впечатление, что человек хотел проходить указателем по битам.
а что-бы анализировать битовое представление нужно использовать битовые операции >> << & | ~
Можно эти, можно арифметические, как я сказал. Арифметические намного легче воспринимаются, имхо. Хотя от задачи тоже зависит.


ANTON_AL, на скриншоте вызов count или count
count


программа работать не будет, и это правильно, ибо у типа bool есть только 2 значения: true и false. всё остальное - кривизна. никакие 0, 1, 255, -999, 1000000 и прочие чудеса к bool неприминимы.выход - написать отдельную шаблонную спецификацию для boolT tmp = pSrc[y*pitch + x * step];bool a = static_cast(tmp != 0);кому же такая индексация по указателю приведет к UB при использовани двумерного динамического массива (BYTE**).


Rififi, да, я к этому и сколняюсь.Я во втором ответе приводил пример, который демонстрирует интерпретацию памяти и побитовые свойства ==.
    BYTE a = 255;    BYTE b = 1;    if ( *(bool*)&a == *(bool*)&b )        std::cout << "true";    else        std::cout << "false";    if ( (bool)a == (bool)b )        std::cout << "this will be ok";
. . . но небольшая модификация меня смутила:
    BYTE a = 255;    BYTE b = 1;    if ( (bool)*(bool*)&a == (bool)*(bool*)&b )        std::cout << "true";    else        std::cout << "false"; //почему опять попадаем сюда ??    if ( (bool)a == (bool)b )        std::cout << "this will be ok";
Ведь, наскольно я понимаю, выражение
(bool)*(bool*)&a
даёт уже приведение значения к типу bool, а не интерпретацию памяти. Но, на практике -  это не так. Что в таком случае происходит??


//почему опять попадаем сюда ??
очевидно у компилятора другие соображения.если посмотреть на ассемблерный листиг условия, то он выглядит так:[nocode]if ( (bool)*(bool*)&a == (bool)*(bool*)&b )0055C18C  movzx       eax,byte ptr [a] 0055C190  movzx       ecx,byte ptr  0055C194  cmp         eax,ecx [/nocode]то есть происходит именно [B]интерпретация памяти, даже несмотря на явный кастингДобавлено через 5 минут и 54 секундыPS. как тут бишь отменить парсинг BB-кодов? что-то не нашел... ну и хрен с ними (:


Вот в этом и вопрос - как написать универсальную функцию, которая подсчитывает количество элементов с указанным значением ?Основное требование: если в неё подать массив типа BYTE, то она должна подсчитать количество ненулевых значений ( с шаблонным параметром - bool )
так ты приводишь указатель, 255 от этого не станет равным true, который в свою очередь равен 1(скорее всего) 
для этого нужно перегрузить функцию сравнения, например так :
template< class T >int count( T *pSrc, int width, int height, int pitch, int step, T val , bool (cmp)(const T&, const T&)){    int count = 0;    for ( int y = 0; y < height; y++ )        for ( int x = 0; x < width; x++ )        {            T a = pSrc[y*pitch + x * step];            T b = val;            if ( cmp(a,b) )            count++;        }    return count;}bool cmp_bool (const bool& lhs, const bool& rhs){     return (lhs? 1:0) == (rhs? 1:0);}....            std::cout << count<bool>( (bool*)test, 4, 4, 4, 1, true, cmp_bool );
естественно cmp_bool можно заменить на cmp со специализацией под bool и дабавить ее по умолчанию в список параметров для count