Couple of questions/issues:
The code below isn't compiling (see comments below)
Would I have to override the hash function for Bar and Baz too if I wanted them to return id() as their hash value?
#include <functional>
class Foo
{
public:
Foo(short id);
short id() const;
private:
const short id_;
};
class Bar : public Foo {};
class Baz : public Foo {};
Foo::Foo(short id) :
id_(id)
{}
short Foo::id() const
{
return id_;
}
namespace std
{
template <> struct hash<Foo> //hash is not a class template
{ //explicit specialization of non-template std::hash
size_t operator()(const Foo& foo) const
{
return hash<short>()(foo.id()); //std::hash is not a template
}
};
}
The problem is a const reference is being passed to hash::operator() but Foo::id() is not declared const. This prevents you from calling id() on any const instance of Foo. To fix this just declare the function const like so
class Foo
{
public:
short id() const;
};
If you are defining an instance of std::hash and passing one of the derived classes as the template argument you will need to provide a specialization for each one. If you are simply passing an instance of a derived class to std::hash<Foo> you do not need to provide specializations for them.
Also make sure you are using a C++11 compiler (with C++11 mode enabled if necessary) and are including the <functional> header as mentioned by Kerrek in the comments.
Related
I have a class template that implements a number of functions. I want to be able to also add specialized version of this class which has only a few functions that override those of the base, when a specific type is declared. I know I could achieve this with a class template and explicit specializations of it. However I also want to:
Have the explicit specializations uniquely named, similar to how a base and derived class are uniquely named.
Call the Base functions from an instantiated Derived object, either inside a Derived function, or explicitly as below with obj1.Foo
This is the (simplified) example code I am trying to make work:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
template<>
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
In myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
template<>
Derived::Bar(int& input) { // Do something int-dependent }
In main.cpp
int main()
{
Base<int> obj1 = new Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
However this code fails with the explicit specialization of non-template Derived error, among others. I've read a lot of StackOverflow threads to get me this far, but I haven't found any that have helped me make this compile. So my questions are:
Is combining class templates with class inheritance possible in this way?
Why does the compiler label the Derived class a non-template despite me explicitly using that keyword?
What is the correct syntax that will make this code work? (assuming what I am trying to do is possible)
EDIT: Following the suggesting of HTNW, I can turn Derived into a regular class by removing the template<> prefix. This will allow everything to compile up to obj1.Foo(input). It seems that the instantiated Derived class can't find or access the base Foo function.
Thanks to ravnsgaard and HTNW for the helpful suggestions which got me to a solution. The key was to remove the template<> keyword from the Derived class (because I wanted it to be a class and not a class template) and declaration of Base<int> at the end of the source file. So the working code looks like this:
In myClasses.h
template<typename T>
class Base
{
public:
void Foo (T& input);
virtual void Bar (T& input);
}
class Derived : public Base<int>
{
public:
void Bar (int& input) override;
}
in myClasses.cpp
template<typename T>
Base::Foo(T& input) { // Do something generic }
template<typename T>
Base::Bar(T& input) { // Do something generic }
Derived::Bar(int& input) { // Do something int-dependent }
template class Base<int>; // VERY IMPORTANT.
In main.cpp
int main()
{
Base<int> &&obj1 = Derived();
obj1.Foo(input); // Runs Base::Foo
obj1.Bar(input); // Runs Derived::Bar
}
In particular, without the template class Base<int>; declaration at the end of myClasses.cpp, the call to obj1.Foo will fail with an error complaining that Derived has no such function.
I'm trying to make a CRTP Singleton. There's a couple examples on here already. I'm not sure how mine is different or why it fails to compile. First attempt:
template<class Impl>
class Base
{
public:
static const Impl& getInstance();
static int foo(int x);
private:
static const Impl impl{};
};
template<class Impl> inline
const Impl& Base<Impl>::getInstance()
{
return impl;
}
template<class Impl> inline
int Base<Impl>::foo(int x)
{
return impl.foo_impl(x);
}
class Derived1 : public Base<Derived1>
{
public:
int foo_impl(int x) const;
};
int Derived1::foo_impl(int x) const
{
return x + 3;
}
int main(int argc, char** argv)
{
const Derived1& d = Derived1::getInstance();
std::cout << Derived1::foo(3) << std::endl;
return 0;
}
g++ 7.4.0 tells me: error: in-class initialization of static data member ‘const Derived1 Base<Derived1>::impl’ of incomplete type.
Well. Ok then. Not sure why that type isn't complete. Try:
. . .
private:
static constexpr Impl impl{};
};
Now we fail at link time: undefined reference to 'Base<Derived1>::impl'
Really?! Looks defined and initialized to me... But even if it did link I have a Derived with a non-trivial destructor so then the compiler is going to bomb at compiletime complaining about a non-literal type used in constexpr.
Why isn't Derived1 complete? How can I build this?
The incomplete type error comes from the fact that you use impl in getInstance before it exists.
One way to fix this is initializing impl outside the class definition and make sure it's initialized before being used:
template <class Impl>
const Impl Base<Impl>::impl {};
Try implementing your getInstance function in this way:
template <class Impl>
inline const Impl& Base<Impl>::getInstance() {
static const Impl impl{};
return impl;
}
and then in foo function
template <class Impl>
inline int Base<Impl>::foo(int x) {
return getInstance().foo_impl(x);
}
Demo
To the point of time that Base<Derived1> is instantiated (right at the start of the definition of Derived1) the class Derived1 is incomplete, since it is that untill the end of its declaration. It is indeed not possible to have a complete type in the CRTP, since the derived type will never be complete before you have declared its inheritance.
For non-static data members the only way around that is to use some kind of pointer to the incomplete type (most probably a std::unique_ptr). For static members this does also work, but can also just split the declaration and the definition of a static member. So instead of
template<Impl>
struct Base {
static Impl impl{};
};
write
template<Impl>
struct Base {
static Impl impl;
};
and define it like this
template<Impl>
static Base<Impl>::impl ={};
after Derived1 is complete. (Note that I am not sure how this works for private static members). In my opinion it would be cleanest, if each implementation would do this for itself, i.e. after Derived1 is complete add
template<>
static Base<Derived1>::impl = {};
otherwise getting the order right for multiple implementations will be tricky, I think.
template <typename T>
class Container
{
private:
T data;
public:
Container(T newData) : data(newData) {}
T getData() {return data;}
};
int main()
{
Container* numContainer=new Container<int>(5);
//Do something with numContainer
delete numContainer;
}
This doesn't compile since the type of the Container pointer must be specified, such as int.
This can, as I found out after some quick googling, be dealt with by creating a ContainerBase class which is not a template and let Container derive from it. Letting the pointer be of type ContainerBase will however not let me use methods such as getData() since it returns type T and can therefore not be declared in the ContainerBase class.
Can I somehow have a pointer which can point to an instance of a template class of any type, even if the class contains methods such as in the example above?
Can I somehow have a pointer which can point to an instance of a template class of any type, even if the class contains methods such as in the example above?
No you can't, for your template class to be instantiated the compiler must know the type of T. Think of a class template as a blueprint of a class and not as a concrete definition of a class. For every type you specify for your template class (e.g., Container<int>) the compiler generates a separate definition. The compiler when it sees the name of your template class (e.g., Container) can't deduce its type out of thin air.
IMHO, The best you can do in order to avoid explicitly specifying every time the type of the template is to use aliases like the example below:
template <typename T>
class Container {
T data;
public:
Container(T const &newData) : data(newData) {}
T getData() const {return data;}
};
using iContainer = Container<int>;
int main() {
iContainer* numContainer=new iContainer(5);
//Do something with numContainer
delete numContainer;
}
Or use runtime polymorphism as you've already mentioned in combination with use of dynamic_cast like the example below:
class BaseContainer {
public:
virtual ~BaseContainer() {}
};
template <typename T>
class Container : public BaseContainer {
T data;
public:
Container(T const &newData) : data(newData) {}
T getData() const {return data;}
};
int main() {
BaseContainer *numContainer = new Container<int>(5);
Container<int> *ptr = dynamic_cast<Container<int>*>(numContainer);
if(ptr) std::cout << ptr->getData() << std::endl;;
delete numContainer;
}
LIVE DEMO
I have two classes (ClassA and ClassB) who both have two methods (compare and converge). These methods work exactly the same way, but these classes are not related polymorphically (for good reason). I would like to define a function template that both of these classes can explicitly instantiate as a member but I'm getting errors because the methods use "this" and when I turn them into a template the compiler throws an error because they're not member functions.
Is this impossible because of that limitation? Or is there some way to use "this" inside of a function template that is not declared as part of a template class. I've done some research and found nothing.
Logic.h
template <class T>
T* compare(const T& t) {
//stuff involving this
}
template <class T>
T* converge(const T& t,bool b) {
//other stuff involving this
}
ClassA.cpp
#include "ClassA.h"
#include "Logic.h"
//constructors
template ClassA* ClassA::compare(const ClassA& t) const;
template ClassA* ClassA::converge(const ClassA& t,bool b) const;
//other methods
classB is similar.
Any help is appreciated!
I believe you can use CRTP here. Here is an example, you can omit the friend declaration in case you can do the compare using only public members:
template<class T>
class comparer
{
public:
T* compare(const T& t)
{
//Use this pointer
bool b = static_cast<T*>(this)->m_b == t.m_b;
return NULL;
}
};
class A : public comparer<A>
{
public:
friend class comparer<A>;
A() : m_b(0)
{
}
private:
int m_b;
};
class B : public comparer<B>
{
public:
friend class comparer<B>;
B() : m_b(0)
{
}
private:
int m_b;
};
int main()
{
A a1,a2;
A* p = a1.compare(a2);
B b1,b2;
B* p1 = b1.compare(b2);
return 0;
}
You can't use this inside non-member function. What you can do is create template function and declare it as a friend of your classA and classB. But classA and classB members that are accessed by template function must have the same names.
template <typename T>
bool compare(const T& t1, const T& t2)
{
return t1.val == t2.val;
}
class A
{
public:
template <typename T>
friend bool compare(const T&, const T&);
bool compare(const A& a)
{
return ::compare(*this, a);
}
private:
int val;
};
A a1, a2;
a1.compare(a2);
What you want is impossible. Member functions must be declared and defined as members. The same goes for member function templates, from which member functions can be instantiated.
But (why) do those functions have to be members? If those functions don't need access to private stuff in these classes, make them free function templates. The whole STL (which, BTW, is but one part of the C++ standard library) is build around non-member functions and achieves a much higher level of abstraction as any OO container lib coming before it ever did.
Contrary to popular believe, non-member functions generally increase encapsulation:
If you're writing a function that can be implemented as either a member or as a non-friend non-member, you should prefer to implement it as a non-member function. That decision increases class encapsulation. When you think encapsulation, you should think non-member functions.
If I have a class with a private construction, using boost::make_shared() to construct a shared_ptr of that class from within a member function of that class will issue a compiler error using gcc 4.6.
#include "boost/shared_ptr.hpp"
#include "boost/make_shared.hpp"
class Foo
{
private:
Foo(int a){};
public:
static boost::shared_ptr<Foo> do_foo(){ return boost::make_shared<Foo>(5); }
friend template boost::shared_ptr<Foo> boost::make_shared<Foo>( Arg1 && arg1, Args && ... args );
}
int main()
{
auto f = Foo::do_foo();
}
A call to Foo::do_foo will result in a compiler error.
Any thoughts?
Unfortunately, it is not specified which function actually calls the constructor in make_shared, so you cannot make that function a friend. If you have a class with a private constructor like this then you thus cannot construct an instance with make_shared.
However, what you can do is create a derived class with a public constructor that calls the appropriate base class constructor, and make that derived class a friend (so it can call the private constructor):
class Foo
{
private:
Foo(int a){};
public:
static boost::shared_ptr do_foo();
friend class DerivedFoo;
};
class DerivedFoo: public Foo
{
public:
DerivedFoo(int a):
Foo(a)
{}
};
boost::shared_ptr<Foo> Foo::do_foo(){ return boost::make_shared<DerivedFoo>(5); }
If DerivedFoo is in an anonymous namespace in the .cpp file that defines do_foo then functions in other .cpp files will still not be able to construct any instances of Foo directly, and users will not be able to tell that what they have is actually a DerivedFoo.
You need, at the very least, to provide template arguments in a few places.
class Foo
{
private:
Foo(int a){};
public:
static boost::shared_ptr<Foo> do_foo(){ return boost::make_shared<Foo>(5); }
friend template boost::shared_ptr<Foo> boost::make_shared<Foo>( Arg1 && arg1, Args && ... args );
}