I try to compile code for Gaussian Blur from Librow article 9. When compile, I get these errors: ‘Buffer’ was not declared in this scope (gaussianblur.cpp, line 139) ‘Buffer’ was not declared in this scope (gaussianblur.cpp, line 158) ‘Buffer’ was not declared in this scope (gaussianblur.cpp, line 167) ‘Buffer’ was not declared in this scope (gaussianblur.cpp, line 185 ‘Buffer’ was not declared in this scope (gaussianblur.h, line 72) ‘Size’ was not declared in this scope (gaussianblur.cpp, line 145) ‘Size’ was not declared in this scope (gaussianblur.cpp, line 158) ‘Size’ was not declared in this scope (gaussianblur.cpp, line 163) ‘Size’ was not declared in this scope (gaussianblur.cpp, line 183) class ‘TGaussianBlur<T>::CExtension’ does not have any field named ‘Buffer’ (gaussianblur.h, line 70) As far as I understand, Buffer should be inherited in CExtension. Don't understand where is a problem. Thanks! gaussianblur.h Code: C++ Code: #include <stdio.h> #ifndef _GAUSSIANBLUR_H_ #define _GAUSSIANBLUR_H_ template <class T = double> class TGaussianBlur { public: // 1D GAUSSIAN BLUR // pSignal - input signal; // pResult - output signal, NULL for inplace processing // N - length of the signal // W - window size, odd positive number bool Filter(T *pSignal, T *pResult, unsigned int N, unsigned int W) const; // 2D GAUSSIAN BLUR // pImage - input image // pResult - output image, NULL for inplace processing // N - width of the image // M - height of the image // W - window size, odd positive number bool Filter(T *pImage, T *pResult, unsigned int N, unsigned int M, unsigned int W) const; protected: // Internal auxiliary structure - data array size descriptor struct CSize { unsigned int x; // Array width unsigned int y; // Array height // Default constructor CSize(): x(0), y(0) {} // Constructor with initialization CSize(unsigned int _x, unsigned int _y): x(_x), y(_y) {} // Initialization void Set(unsigned int _x, unsigned int _y) { x = _x; y = _y; } // Area unsigned int Area() const { return x * y; } }; // Internal auxiliary structure - array descriptor struct CArray { CSize Size; // Array size T *Buffer; // Element buffer // Default constructor CArray(): Buffer(NULL) {} // Constructors with initialization CArray(T *_Buffer, const CSize &_Size): Buffer(_Buffer), Size(_Size) {} CArray(T *_Buffer, unsigned int _N): Buffer(_Buffer), Size(_N, 1) {} }; // Internal auxiliary structure - array extension descriptor struct CExtension: public CArray { unsigned int Margin; // Extension margins enum EMode {ModeHorizontal, ModeVertical}; // Default cosntructor CExtension(): Buffer(0), Margin(0), Mode(ModeHorizontal) {} // Destructor ~CExtension() { if (Buffer) delete[] Buffer; } // Mode setting void SetMode(EMode _Mode) { Mode = _Mode; } // Extension memory allocation bool Allocate(unsigned int _N, unsigned int _W) { return _Allocate(CSize(_N, 1), _W >> 1); } bool Allocate(const CSize &_Size, unsigned int _W) { return _Allocate(_Size, _W >> 1); } // Pasting data into extension from data array void Paste(const T * _Start); // Extension void Extend(); protected: EMode Mode; // Current mode // Extension memory allocation bool _Allocate(const CSize &_Size, unsigned int _Margin); }; // Internal auxiliary structure - filter window descriptor struct CWindow { double *Weights; // Window weights unsigned int Size; // Window size // Default constructor CWindow(): Weights(NULL), Size(0), Correction(.5 - double(T(.5))) {} // Destructor ~CWindow() { if (Weights) delete[] Weights; } // Filter window creation bool Create(unsigned int _Size); // FILTER WINDOW APPLICATION // _Element - start element in signal/image T Apply(const T *_Element) const { // Apply filter - calculate weighted mean double Sum = 0.; const double *WeightIter = Weights; const T *ElIter = _Element; const double *const End = Weights + Size; while (WeightIter < End) Sum += *(WeightIter++) * double(*(ElIter++)); return T(Sum + Correction); } protected: const double Correction; }; // Internal auxiliary functions - check input data consistency bool Consistent(const T *_Image, const CSize &_Size, unsigned int _W) const { return _Image && _Size.x && _Size.y && _W && _Size.x > (_W >> 1) && _Size.y > (_W >> 1) && _W & 1; } bool Consistent(const T *_Signal, unsigned int _N, unsigned int _W) const { return _Signal && _N && _W && _N > (_W >> 1) && _W & 1; } }; // Include implementation file #include "gaussianblur.cpp" #endif gaussianblur.cpp Code: C++ Code: #ifndef _GAUSSIANBLUR_CPP_ #define _GAUSSIANBLUR_CPP_ // Include declaration file #include "gaussianblur.h" // Include math library #include <math.h> // 1D GAUSSIAN BLUR // pSignal - input signal; // pResult - output signal, NULL for inplace processing // N - length of the signal // W - window size, odd positive number template <class T> bool TGaussianBlur<T>::Filter(T *pSignal, T *pResult, unsigned int N, unsigned int W) const { // Check input data cosnsitency if (!Consistent(pSignal, N, W)) return false; // Allocate extension CExtension Extension; if (!Extension.Allocate(N, W)) return false; // Create signal descriptor const CArray Signal(pSignal, N); // Paste signal into extension Extension.Paste(Signal.Buffer); // Extend signal Extension.Extend(); // Create filter window CWindow Window; if (!Window.Create(W)) return false; // Extension iterator const T *ExtIter = Extension.Buffer; // Extension stop position const T *const ExtStop = Extension.Buffer + Extension.Size.x; // Result iterator T *ResIter = pResult ? pResult : pSignal; // Filter - apply to every element while (ExtIter < ExtStop) *(ResIter++) = Window.Apply(ExtIter++); // Succeeded return true; } // 2D GAUSSIAN BLUR // pImage - input image // pResult - output image, NULL for inplace processing // N - width of the image // M - height of the image // W - window size template <class T> bool TGaussianBlur<T>::Filter(T *pImage, T *pResult, unsigned int N, unsigned int M, unsigned int W) const { // Check input data consistency if (!Consistent(pImage, CSize(N, M), W)) return false; // Allocate extension CExtension Extension; if (!Extension.Allocate(CSize(N, M), W)) return false; // Create image descriptor CArray Image(pImage, CSize(N, M)); // Create filter window CWindow Window; if (!Window.Create(W)) return false; // Stop postion const T * ExtStop = Extension.Buffer + Extension.Size.x; // Result iterator T *ResIter = pResult ? pResult : pImage; // Image iterator const T *ImIter = Image.Buffer; // Image stop position const T * ImStop = Image.Buffer + Image.Size.Area(); // Filter line by line while (ImIter < ImStop) { // Paste image line into extension Extension.Paste(ImIter); // Extend image line Extension.Extend(); // Extension iterator const T *ExtIter = Extension.Buffer; // Apply filter to every pixel of the line while (ExtIter < ExtStop) *(ResIter++) = Window.Apply(ExtIter++); // Move to the next line ImIter += Image.Size.x; } // Initialize image descriptor with filter result Image.Buffer = pResult ? pResult : pImage; // Set vertical extension mode Extension.SetMode(CExtension::ModeVertical); // Extension stop position ExtStop = Extension.Buffer + Extension.Size.y; // Result column iterator T *ResColumnIter = pResult ? pResult : pImage; // Image iterator ImIter = Image.Buffer; // Image stop position ImStop = Image.Buffer + Image.Size.x; // Filter column by column while (ImIter < ImStop) { // Paste image column into extension Extension.Paste(ImIter++); // Extend image column Extension.Extend(); // Extension iterator const T *ExtIter = Extension.Buffer; // Result pixel iterator ResIter = ResColumnIter; // Apply fitler to every pixel of the column while (ExtIter < ExtStop) { *ResIter = Window.Apply(ExtIter++); ResIter += Image.Size.x; } // Move to the next column ++ResColumnIter; } // Succeeded return true; } // EXTENSION MEMORY ALLOCATION // _Size - signal/image size // _Margin - extension margins template <class T> bool TGaussianBlur<T>::CExtension::_Allocate(const CSize &_Size, unsigned int _Margin) { // Allocate extension buffer Buffer = new T[(_Size.x > _Size.y ? _Size.x : _Size.y) + (_Margin << 1)]; // Check buffer allocation if (!Buffer) // Buffer allocation failed return false; // Initialize size descriptors Size = _Size; Margin = _Margin; // Succeeded return true; } // PASTING DATA LINE/COLUMN INTO EXTENSION FROM DATA ARRAY // _Start - start postion in image/signal to paste from template <class T> void TGaussianBlur<T>::CExtension::Paste(const T *const _Start) { if (Mode == ModeHorizontal) { // Paste line memcpy(Buffer + Margin, _Start, Size.x * sizeof(T)); } else { // Stop position const T *const Stop = _Start + Size.Area(); // Array iterator const T *ArrIter = _Start; // Extension iterator T *ExtIter = Buffer + Margin; // Paste array column element by element while (ArrIter < Stop) { // Copy line *(ExtIter++) = *ArrIter; // Jump to the next line ArrIter += Size.x; } } } // EXTENSION CREATION template <class T> void TGaussianBlur<T>::CExtension::Extend() { // Line size const unsigned int Line = Mode == ModeHorizontal ? Size.x : Size.y; // Stop position const T *const Stop = Buffer - 1; // Left extension iterator T *ExtLeft = Buffer + Margin - 1; // Left array iterator const T *ArrLeft = ExtLeft + 2; // Right extension iterator T *ExtRight = ExtLeft + Line + 1; // Left array iterator const T *ArrRight = ExtRight - 2; // Create extension line element by element while (ExtLeft > Stop) { // Left extension *(ExtLeft--) = *(ArrLeft++); // Right extension *(ExtRight++) = *(ArrRight--); } } // FILTER WINDOW CREATION // _Size - window size template <class T> bool TGaussianBlur<T>::CWindow::Create(unsigned int _Size) { // Allocate window buffer Weights = new double[_Size]; // Check allocation if (!Weights) // Window buffer allocation failed return false; // Set window size Size = _Size; // Window half const unsigned int Half = Size >> 1; // Central weight Weights[Half] = 1.; // The rest of weights for (unsigned int Weight = 1; Weight < Half + 1; ++Weight) { // Support point const double x = 3.* double(Weight) / double(Half); // Corresponding symmetric weights Weights[Half - Weight] = Weights[Half + Weight] = exp(-x * x / 2.); } // Weight sum double k = 0.; for (unsigned int Weight = 0; Weight < Size; ++Weight) k += Weights[Weight]; // Weight scaling for (unsigned int Weight = 0; Weight < Size; ++Weight) Weights[Weight] /= k; // Succeeded return true; } #endif
Hi choxy, First of all, Welcome to G4EF. Now, you want to use inheritance with structures. :thinking: Well, that's entirely possible. But, I don't know why this does not work. ! :surprised: MinGW on my machines gives the same errors as you mentioned ! Anyway, you can safely simulate inheritance this way : Code: struct BaseStructure { . . . } struct DerivedStructure { BaseStructure Parent; . . . // Now you can access members of BaseStructure through Parent . . . } So, after modification, your Gaussian Blur program becomes : (*) gaussianblur.h Code: #include <stdio.h> #ifndef _GAUSSIANBLUR_H_ #define _GAUSSIANBLUR_H_ template <class T = double> class TGaussianBlur { public: // 1D GAUSSIAN BLUR // pSignal - input signal; // pResult - output signal, NULL for inplace processing // N - length of the signal // W - window size, odd positive number bool Filter(T *pSignal, T *pResult, unsigned int N, unsigned int W) const; // 2D GAUSSIAN BLUR // pImage - input image // pResult - output image, NULL for inplace processing // N - width of the image // M - height of the image // W - window size, odd positive number bool Filter(T *pImage, T *pResult, unsigned int N, unsigned int M, unsigned int W) const; protected: // Internal auxiliary structure - data array size descriptor struct CSize { unsigned int x; // Array width unsigned int y; // Array height // Default constructor CSize(): x(0), y(0) {} // Constructor with initialization CSize(unsigned int _x, unsigned int _y): x(_x), y(_y) {} // Initialization void Set(unsigned int _x, unsigned int _y) { x = _x; y = _y; } // Area unsigned int Area() const { return x * y; } }; // Internal auxiliary structure - array descriptor struct CArray { CSize Size; // Array size T *Buffer; // Element buffer // Default constructor CArray(): Buffer(NULL) {} // Constructors with initialization CArray(T *_Buffer, const CSize &_Size): Buffer(_Buffer), Size(_Size) {} CArray(T *_Buffer, unsigned int _N): Buffer(_Buffer), Size(_N, 1) {} }; // Internal auxiliary structure - array extension descriptor struct CExtension { CArray parent; unsigned int Margin; // Extension margins enum EMode {ModeHorizontal, ModeVertical}; // Default cosntructor CExtension(): parent(), Margin(0), Mode(ModeHorizontal) {} // Destructor ~CExtension() { if (parent.Buffer) delete[] parent.Buffer; } // Mode setting void SetMode(EMode _Mode) { Mode = _Mode; } // Extension memory allocation bool Allocate(unsigned int _N, unsigned int _W) { return _Allocate(CSize(_N, 1), _W >> 1); } bool Allocate(const CSize &_Size, unsigned int _W) { return _Allocate(_Size, _W >> 1); } // Pasting data into extension from data array void Paste(const T * _Start); // Extension void Extend(); protected: EMode Mode; // Current mode // Extension memory allocation bool _Allocate(const CSize &_Size, unsigned int _Margin); }; // Internal auxiliary structure - filter window descriptor struct CWindow { double *Weights; // Window weights unsigned int Size; // Window size // Default constructor CWindow(): Weights(NULL), Size(0), Correction(.5 - double(T(.5))) {} // Destructor ~CWindow() { if (Weights) delete[] Weights; } // Filter window creation bool Create(unsigned int _Size); // FILTER WINDOW APPLICATION // _Element - start element in signal/image T Apply(const T *_Element) const { // Apply filter - calculate weighted mean double Sum = 0.; const double *WeightIter = Weights; const T *ElIter = _Element; const double *const End = Weights + Size; while (WeightIter < End) Sum += *(WeightIter++) * double(*(ElIter++)); return T(Sum + Correction); } protected: const double Correction; }; // Internal auxiliary functions - check input data consistency bool Consistent(const T *_Image, const CSize &_Size, unsigned int _W) const { return _Image && _Size.x && _Size.y && _W && _Size.x > (_W >> 1) && _Size.y > (_W >> 1) && _W & 1; } bool Consistent(const T *_Signal, unsigned int _N, unsigned int _W) const { return _Signal && _N && _W && _N > (_W >> 1) && _W & 1; } }; // Include implementation file #include "gaussianblur.cpp" #endif (*) gaussianblur.cpp Code: #ifndef _GAUSSIANBLUR_CPP_ #define _GAUSSIANBLUR_CPP_ // Include declaration file #include "gaussianblur.h" // Include math library #include <math.h> // 1D GAUSSIAN BLUR // pSignal - input signal; // pResult - output signal, NULL for inplace processing // N - length of the signal // W - window size, odd positive number template <class T> bool TGaussianBlur<T>::Filter(T *pSignal, T *pResult, unsigned int N, unsigned int W) const { // Check input data cosnsitency if (!Consistent(pSignal, N, W)) return false; // Allocate extension CExtension Extension; if (!Extension.Allocate(N, W)) return false; // Create signal descriptor const CArray Signal(pSignal, N); // Paste signal into extension Extension.Paste(Signal.Buffer); // Extend signal Extension.Extend(); // Create filter window CWindow Window; if (!Window.Create(W)) return false; // Extension iterator const T *ExtIter = Extension.Buffer; // Extension stop position const T *const ExtStop = Extension.Buffer + Extension.Size.x; // Result iterator T *ResIter = pResult ? pResult : pSignal; // Filter - apply to every element while (ExtIter < ExtStop) *(ResIter++) = Window.Apply(ExtIter++); // Succeeded return true; } // 2D GAUSSIAN BLUR // pImage - input image // pResult - output image, NULL for inplace processing // N - width of the image // M - height of the image // W - window size template <class T> bool TGaussianBlur<T>::Filter(T *pImage, T *pResult, unsigned int N, unsigned int M, unsigned int W) const { // Check input data consistency if (!Consistent(pImage, CSize(N, M), W)) return false; // Allocate extension CExtension Extension; if (!Extension.Allocate(CSize(N, M), W)) return false; // Create image descriptor CArray Image(pImage, CSize(N, M)); // Create filter window CWindow Window; if (!Window.Create(W)) return false; // Stop postion const T * ExtStop = Extension.Buffer + Extension.Size.x; // Result iterator T *ResIter = pResult ? pResult : pImage; // Image iterator const T *ImIter = Image.Buffer; // Image stop position const T * ImStop = Image.Buffer + Image.Size.Area(); // Filter line by line while (ImIter < ImStop) { // Paste image line into extension Extension.Paste(ImIter); // Extend image line Extension.Extend(); // Extension iterator const T *ExtIter = Extension.Buffer; // Apply filter to every pixel of the line while (ExtIter < ExtStop) *(ResIter++) = Window.Apply(ExtIter++); // Move to the next line ImIter += Image.Size.x; } // Initialize image descriptor with filter result Image.Buffer = pResult ? pResult : pImage; // Set vertical extension mode Extension.SetMode(CExtension::ModeVertical); // Extension stop position ExtStop = Extension.Buffer + Extension.Size.y; // Result column iterator T *ResColumnIter = pResult ? pResult : pImage; // Image iterator ImIter = Image.Buffer; // Image stop position ImStop = Image.Buffer + Image.Size.x; // Filter column by column while (ImIter < ImStop) { // Paste image column into extension Extension.Paste(ImIter++); // Extend image column Extension.Extend(); // Extension iterator const T *ExtIter = Extension.Buffer; // Result pixel iterator ResIter = ResColumnIter; // Apply fitler to every pixel of the column while (ExtIter < ExtStop) { *ResIter = Window.Apply(ExtIter++); ResIter += Image.Size.x; } // Move to the next column ++ResColumnIter; } // Succeeded return true; } // EXTENSION MEMORY ALLOCATION // _Size - signal/image size // _Margin - extension margins template <class T> bool TGaussianBlur<T>::CExtension::_Allocate(const CSize &_Size, unsigned int _Margin) { // Allocate extension buffer parent.Buffer = new T[(_Size.x > _Size.y ? _Size.x : _Size.y) + (_Margin << 1)]; // Check buffer allocation if (!parent.Buffer) // Buffer allocation failed return false; // Initialize size descriptors parent.Size = _Size; Margin = _Margin; // Succeeded return true; } // PASTING DATA LINE/COLUMN INTO EXTENSION FROM DATA ARRAY // _Start - start postion in image/signal to paste from template <class T> void TGaussianBlur<T>::CExtension::Paste(const T *const _Start) { if (Mode == ModeHorizontal) { // Paste line memcpy(parent.Buffer + Margin, _Start, parent.Size.x * sizeof(T)); } else { // Stop position const T *const Stop = _Start + parent.Size.Area(); // Array iterator const T *ArrIter = _Start; // Extension iterator T *ExtIter = parent.Buffer + Margin; // Paste array column element by element while (ArrIter < Stop) { // Copy line *(ExtIter++) = *ArrIter; // Jump to the next line ArrIter += parent.Size.x; } } } // EXTENSION CREATION template <class T> void TGaussianBlur<T>::CExtension::Extend() { // Line size const unsigned int Line = Mode == ModeHorizontal ? parent.Size.x : parent.Size.y; // Stop position const T *const Stop = parent.Buffer - 1; // Left extension iterator T *ExtLeft = parent.Buffer + Margin - 1; // Left array iterator const T *ArrLeft = ExtLeft + 2; // Right extension iterator T *ExtRight = ExtLeft + Line + 1; // Left array iterator const T *ArrRight = ExtRight - 2; // Create extension line element by element while (ExtLeft > Stop) { // Left extension *(ExtLeft--) = *(ArrLeft++); // Right extension *(ExtRight++) = *(ArrRight--); } } // FILTER WINDOW CREATION // _Size - window size template <class T> bool TGaussianBlur<T>::CWindow::Create(unsigned int _Size) { // Allocate window buffer Weights = new double[_Size]; // Check allocation if (!Weights) // Window buffer allocation failed return false; // Set window size Size = _Size; // Window half const unsigned int Half = Size >> 1; // Central weight Weights[Half] = 1.; // The rest of weights for (unsigned int Weight = 1; Weight < Half + 1; ++Weight) { // Support point const double x = 3.* double(Weight) / double(Half); // Corresponding symmetric weights Weights[Half - Weight] = Weights[Half + Weight] = exp(-x * x / 2.); } // Weight sum double k = 0.; for (unsigned int Weight = 0; Weight < Size; ++Weight) k += Weights[Weight]; // Weight scaling for (unsigned int Weight = 0; Weight < Size; ++Weight) Weights[Weight] /= k; // Succeeded return true; } #endif This one compiles fine ! :happy: Hope this will help. PS : I like your code, it's so well commented !
You shouldn't #include a CPP file inside a .H file. H files are for header information, CPP files are for source. Source files can include headers but not the other way round.
@ xpi0t0s : Are you sure you have carefully observed the above code ?? The template class implementations are in gaussianblur.cpp NOT in gaussianblur.h. So, the .cpp implementation file MUST be included at the end of the .h file. More information here : http://www.ecs.fullerton.edu/~sowell/cs331/TemplateClasses.html
> Are you sure you have carefully observed the above code ?? Heh, you write an H file that #includes a CPP file, and that CPP file #includes the H file, and you ask ME if I'm paying attention. The #ifndef statements will prevent this turning into an infinite loop but you have another problem that means this design is terminally broken. > So, the .cpp implementation file MUST be included at the end of the .h file. No, that doesn't make sense. CPP files contain code and you invoke a compiler on a CPP file. H files contain header information and the whole point of them is to EXCLUDE code and to define stuff ONLY, and they can be #included in multiple CPP files. So if you #include the CPP file in the H file then the first time you #include the H file in another CPP file you will get a bunch of duplicate symbols at link time. In effect you're breaking the whole point of having separate H and CPP files; you can _only_ use gaussianblur.h in gaussianblur.cpp, you can't use it in something that wants to call the functions in gaussianblur.cpp. In fact why don't you try it! Code: // test.cpp #include "gaussianblur.h" void f() { // now call something in gaussianblur.cpp } Compile with somethiing like gcc gaussianblur.cpp test.cpp -o test And let me know how many errors you get.
Thanks for answers! Will make it work then with BaseStructure Parent, not inheritance. (And for the PS.comment about code - it is not my code, it is from Librow article as I mentioned at the start of the thread.)