I am trying to implement a generic hashlist class using templates and I am trying to inherit from the base class but getting lots of compile errors. Here is my code:
#ifndef BASEHASHLIST_H_
#define BASEHASHLIST_H_
#include <string>
#include <boost/unordered_set.hpp>
#include <iostream>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
template <typename T>
class BaseHashList
{
private:
boost::interprocess::interprocess_semaphore m_semaphore;
protected:
boost::unordered_set<T> m_hsHashSet;
typename boost::unordered_set<T>::iterator m_hsIter;
public:
BaseHashList();
};
template <typename T>
BaseHashList<T>::BaseHashList():m_semaphore(1){}
#endif /* BASEHASHLIST_H_ */
And here is the class that is inheriting from the base class:
#ifndef ACCOUNTLIST_H_
#define ACCOUNTLIST_H_
#include "BaseHashList.h"
class AccountList : public BaseHashList<unsigned long>
{
public:
AccountList(std::string p_strFile, unsigned long p_ulMaxAccountNo);
~AccountList(void);
int m_iVersion;
std::string m_strFilePath;
private:
unsigned long m_ulMaxAccountNo;
};
#endif /* ACCOUNTLIST_H_ */
and here is the cpp file:
#include "AccountList.h"
AccountList::AccountList(std::string p_strFile, unsigned long p_ulMaxAccountNo)
: BaseHashList<unsigned long>::m_hsHashSet<unsigned long>(),
m_iVersion(0),
m_strFilePath(p_strFile)
{
m_ulMaxAccountNo = p_ulMaxAccountNo;
}
AccountList::~AccountList(){}
I am receiving a lot of compile time errors such as:
expected template-name before token '<'
expected '(' before token '<'
For such a simple task I spent couple of hours and I am super frustrated, does anybody see what I am doing wrong here?
This initaliser in AccountList's constructor looks wrong to me:
BaseHashList<unsigned long>::m_hsHashSet<unsigned long>()
You should initalise the members of BaseHashList inside a constructor of BaseHashList itself, one will always either explicitly or implicitly be called.
This example is simplified and similarly wrong:
struct A {
int bar;
};
struct B : A {
B() : A::bar(0) {}
};
(saying bar(0) would also be wrong there)
However you can get the desired behaviour:
struct A {
A() : bar(0) {}
int bar;
};
struct B : A {
B() {} // Implicitly calls A::A although we could have explicitly called it
};
The constructor of A gets called and given a chance to initalise its members here still.
When you inherit from a template class, you have to add the template instruction to the child class too :
template <typename T>
class A : public B<T>
You also have to add the template instruction before the definition of constructors and methods :
template <typename T>
A<T>::A() : B<T>() {...}
template <typename T>
A<T>::~A() {...}
Related
Let's say I have the below class:
template <class Base>
struct Wrapper : public Base {
using Base::Base;
// ... add functionality ...
};
And I want some code to be executed during construction after constructors. I can't add a default constructor, because it won't be run when an inherited constructor is used. One idea is this:
template <class Base>
struct Wrapper : public Base {
bool _ = [this] {
// initialize ...
return true;
}();
using Base::Base;
};
This does work perfectly well as long as you place it as the last member, but it wastes memory.
Another way is:
#include <type_traits>
template <class T>
struct InitBlock {
InitBlock() {
static_cast<T*>(this)->init();
}
};
template <class Base>
struct Wrapper : public Base, private InitBlock<Wrapper<Base>> {
private:
template <class T>
friend struct InitBlock;
void init() {
// initialize ...
}
public:
using Base::Base;
};
Which is good, but a bit verbose. And there is nothing protecting init from being called again elsewhere. Also, if Wrapper adds members, this is called before those are initialized, so it's not ideal.
What is a better (safe and low on boilerplate) way of doing this?
As mentioned, we can use [[no_unique_address]] to avoid allocating memory for an empty class. It is honored by all major compilers, except for MSVC. MSVC has its own extension of [[msvc::no_unique_address]]. We wrap a macro around this, and it works fine:
#include <stdio.h>
#ifdef _MSC_VER
#define NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#else
#define NO_UNIQUE_ADDRESS [[no_unique_address]]
#endif
template <class Base>
struct Wrapper : public Base {
private:
NO_UNIQUE_ADDRESS struct Init {} _ = [] {
puts("Wrapper init");
return Init{};
}();
public:
using Base::Base;
};
struct Foo {
int i;
Foo(int i) : i(i) {
printf("Foo(%d)\n", i);
}
};
int main() {
Wrapper<Foo> wfoo(42);
Foo foo(43);
static_assert(sizeof(wfoo) == sizeof(foo));
}
You still have to take care to place it after all other members to make sure they're initialized by the time we touch them, so it's not ideal.
See online
I have stumbled upon something that I don't quite understand. I have a class hierarchy that uses private inheritance where each of the structs defines a different function call operator. Oddly enough, the function call operator from the topmost struct is available in the most derived struct, despite the fact that a using directive is only used in the first derived struct. A regular function foo, though, is not accessible there, as expected. Example:
#include <string>
#include <vector>
#include <iostream>
struct A {
void foo() {}
void operator()(bool) {
std::cout << "bool\n";
}
};
struct B : private A {
using A::foo;
using A::operator();
void operator()(std::string) {}
};
struct C : private B {
using B::operator();
void operator()(std::vector<int>) {}
};
struct D : private C {
using C::operator();
void operator()(std::vector<double>) {}
};
int main() {
D d{};
d(false); // <-- works!
//d.foo(); // <-- error: ‘void A::foo()’ is private within this context
return 0;
}
I happened upon this while trying to implement the C++17 overload object for use with boost::apply_visitor using pre-C++17 code. I solved it using recursive inheritance, where each object pulls in the function call operator of its direct base class like so:
template<typename T, typename... Ts>
struct visitor : private T, private visitor<Ts...> {
using T::operator();
using visitor<Ts...>::operator();
visitor(T func, Ts... tail) : T{ std::move(func) }, visitor<Ts...>{ std::move(tail)... } {}
};
template<typename T>
struct visitor<T> : private T {
using T::operator();
visitor(T func) : T{ std::move(func) } {}
};
template<typename... Ts>
visitor<Ts...> make_visitor(Ts&&... funcs) {
return visitor<Ts...>{ std::forward<Ts>(funcs)... };
}
I wanted to understand why all of the operators are available in the most derived object. That's how I came up with the above example. Compiler is g++ 11.1.0.
Can anyone enlighten me as to what's going on here?
As pointed out by others in comments, it turns out I just had an error in my thinking. The using pulls in all the operators available in the respective base class, including the ones that were imported by the base class itself, and therefore all the operators will be available in the bottommost object. foo, on the other hand, is just handed down to B.
I'm working on creating an "Array_Base" interface that will allow a user to create either a fixed array or an expandable array of any type. Right now I can't even get the regular Array to work.
I've broken the problem down to a few of its simplest components to try and isolate the issue. I believe it has something to do with my instantiation. I'm using Visual Studio to run the code.
Array_Base.h
#ifndef _ARRAY_BASE_H_
#define _ARRAY_BASE_H_
#include <cstring> // for size_t definition
template <typename T>
class Array_Base
{
public:
typedef T type;
//Default Constructor
virtual void Array_Base(void) = 0;
// Destructor.
virtual ~Array_Base(void) = 0;
protected:
/// Pointer to the actual data.
T* data_;
/// Current size of the array.
size_t cur_size_;
/// Maximum size of the array.
size_t max_size_;
};
#endif // !defined _ARRAY_H_
Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <cstring> // for size_t definition
#include "Array_Base.h"
template <typename T>
class Array : public Array_Base
{
public:
/// Type definition of the element type.
typedef T type;
/// Default constructor.
Array (void);
///Destructor
~Array (void);
};
#include "Array.cpp"
#include "Array.inl"
#endif // !defined _ARRAY_H_
Array.cpp
#include <stdexcept> // for std::out_of_bounds exception
#include <iostream>
#define MAX_SIZE_ 20
template <typename T>
Array <T>::Array (void)
:data_(new T[MAX_SIZE_]),
cur_size_(0),
max_size_(MAX_SIZE_)
{ }
template <typename T>
Array <T>::~Array (void)
{
delete[] this->data_;
this->data_ = nullptr;
}
Main.cpp:
#include "Array.h"
int main(void)
{
Array_Base<int>* arr = new Array<int>();
delete arr;
}
I keep getting an error that says: "a value type of "Array" cannot be used to initialize an entity of type "Array_Base" from a red line that appears under the "new" operator in main.
Any help would be greatly appreciated. Thank you!
template <typename T>
class Array : public Array_Base
Array_Base does not name a class. You need to provide it with a template argument.
Do you mean this?
template <typename T>
class Array : public Array_Base<T>
I'm experiencing a problem accessing a protected class member from a class template derived from another class template. I have three class templates, the second derived from the first, and and third one derived from the second. Specifically,
class1.h:
template <typename T> class class1
{
protected:
T data;
int a;
public:
class1();
void someMethod();
};
class2.h:
#include "class1.h"
template <typename T> class class2: public class1<T>
{
using class1<T>::a;
T otherData;
public:
class2();
};
class3.h:
#include "class2.h"
template <typename T> class class3: public class2<T>
{
using class2<T>::a;
public:
class3();
};
class2.cpp:
#include "class2.h"
#include <iostream>
template <typename T> class2<T> :: class2()
{
std::cout<<"Creating class2 object!"<<std::endl;
a = 2;
}
template class class2<double>;
Finally, class3.cpp:
#include "class3.h"
#include <iostream>
template <typename T> class3<T> :: class3()
{
std::cout<<"Creating class3 object!"<<std::endl;
a = 3;
}
template class class3<double>;
When I compile class2.cpp into an object file, like this:
g++ -c -O3 -std=c++11 -Wall -o class2.o class2.cpp
everything goes well. However, a get an error when compiling class3.cpp in the same way. A following error pops up:
In file included from class2.h:4:0,
from class3.h:4,
from class3.cpp:1:
class3.h: In instantiation of ‘class class3<double>’:
class3.cpp:11:16: required from here
class1.h:9:6: error: ‘int class1<double>::a’ is protected
int a;
^
Replacing using class2<T>::a; with using class1<T>::a; in class3 doesn't help.
What's causing this error exactly and how can I avoid it if I really need to access variable a from within class3? Why is it that the first level of inheritance (class2) doesn't detect any problems, and the second one (class3) does? Thanks for any comments.
NOTE: I tried the same type of inheritance, but without templates and removed both lines containing using, and compilation goes well (access to variable a is now granted in class3). The problem definitely has to do with templates.
Your class2 definition is the same as the following:
template <typename T> class class2: public class1<T>
{
private: // default section
using class1<T>::a;
T otherData;
public:
class2();
};
It is because private is the default section for the members of classes. So the a member becomes private here and can't be inherited by the class3. You should explicitly place using class1<T>::a; statement in protected or public section of the class2 definition:
template <typename T> class class2: public class1<T>
{
T otherData;
protected: // <-- added
using class1<T>::a;
public:
class2();
};
Now it can be accessed from the class2 derived classes (including class3).
I don't understand what is wrong with this code.
gcc reports "Client.h:29: error: expected template-name before '<' token"
As far as I'm aware I'm followed the template syntax correctly, but it could be that the error message is confusing me and is not the problem
client.h
class Client : public BaseDll<DllClient> [line 29]
{
..snip..
};
basedll.h
template<typename T>
class BaseDll : public Base
{
public:
..snip..
private:
T* _dll;
};
class Base{
};
template<typename T>
class BaseDll:public Base{
public:
private:
T* _dll;
};
class DllClient{
};
class Clien:public BaseDll<DllClient>
{
};
this compiled for me without problems, so I don't think the problem lies within what you posted. My best bet would be that you made a syntax error in client.h, maybe something as simple as forgetting a semicolon after another class definition or some macro that's messing with your code
I'm so sorry everyone, a school-boy error has been made, BaseDll is declared in another namespace. As soon as I added the namespace qualifier, the problem has gone.
Maybe it's just an easy problem: Have you included basedll.h in client.h?
to cover the basics:
does client-h #include basedll.h? do they user different include guards?
Further troubleshooting:
does it work with a non-template base class?
does it work then you typedef the template instaltiation:
typedef BaseDll<DllClient> tClientBase;
class Client : public tClientBase { ... }
[edit] OK, next:
if you put the following two lines directly under the BaseDll declaration:
template <typename T>
class BaseDll
{ ...
};
class DummyFoo;
typedef BaseDll<DummyFoo> tDummyFoo;
I think you snipped away the problem. Are you including something to define 'DllClient' ?
A possible cause of this is that there is an inter-dependency between the different header files:
// client.h
#ifndef CLIENT
#define CLIENT
#include "base.h"
// ...
class Client : public BaseDll<DllClient>
{
// ..snip..
};
#endif
// base.h
#ifndef BASE
#define BASE
#include "client.h"
template<typename T>
class BaseDll : public Base
{
public:
// ..snip..
private:
T* _dll;
};
#endif
Now imagine we're parsing 'base.cpp' then the preprocessor will do the following:
#include "base.h"
#ifndef BASE <--- BASE unset, keep going
#define BASE
#include "client.h"
#ifndef CLIENT
#define CLIENT
#include "base.h"
#ifndef BASE <--- BASE set, skip base.h, return to client.h
class client
: public BaseDll<DllClient> <-- ERROR, BaseDll not defined.
If this is the problem, then you potentially can get around it by forward declaring the base template in client.h:
// client.h
#ifndef CLIENT
#define CLIENT
// #include "base.h" <-- remove include
template <typename DLL_CLIENT>
class BaseDll;
// ...
class Client : public BaseDll<DllClient>
{
// ..snip..
};
#endif