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 );
}
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 want to enforce shared_ptr for a few classes. I'm using a static factory function to encapsulating private constructors:
#include <memory>
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
auto a = std::shared_ptr<MyClass>(new MyClass());
return a;
}
private:
MyClass();
~MyClass();
}
}
This template fails with C2440, (function-style cast) in VS2017, but works fine in VS2015 and I have no idea why. A make_shared-version works fine in both but requires public constructors.
Any idea which option I'm missing?
Looks like VS2017 complains about accessing destructor from std::shared_ptr, so you may want to declare std::shared_ptr as friend of MyClass. For std::make_shared you can use a trick from this answer How do I call ::std::make_shared on a class with only protected or private constructors?
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
struct make_shared_enabler : MyClass {};
return std::make_shared<make_shared_enabler>();
}
// compiles fine for gcc without friend though
//friend class std::shared_ptr<MyClass>;
private:
MyClass() {}
~MyClass() {}
};
live example
In addition to other answers: if you don't want to declare std::shared_ptr as a friend of your class and you don't want to make your destructor public, you can create a shared_ptr with the custom deleter. For that you will need some method from your MyClass that can access the private destructor and call delete. For example:
class MyClass
{
public:
static std::shared_ptr<MyClass> create() {
auto a = std::shared_ptr<MyClass>(new MyClass(),
[](MyClass* ptr) { destroy(ptr); });
return a;
}
static void destroy(MyClass* ptr) { delete ptr; }
private:
MyClass(){}
~MyClass(){}
};
// later in the source code
auto ptr = MyClass::create();
You can also declare destroy method as non-static and commit a suicide inside (one of a few situations when it actually makes sense).
I am trying to achieve that certain objects within my application can only be constructed as shared_ptr's by a call to a static method called "create".
Of course I could do this by directly adding the static 'create' method to all the respective class. However, this would mean I have to repeat very similar code in almost all my classes. A macro would work, but I do not find this very elegant.
I came up with an alternative way of doing this by deriving all classes from a templated 'BaseObject' class that implements the 'create' method and returns the pointer. This almost works, except that std::make_shared cannot access the constructor of its child class when it is protected.
The non-solution would be to make the child class constructor public (see (1) in the example below). But now Foo can be normally constructed again and this would defeat the entire point. An alternative solution would be to friend BaseObject in the child class and make use of shared_ptr directly (see (2) in the example).
Both solutions put extra burden on the implementer of the child class. Since they have to either find an alternative way of making the constructor non-public or put a friend declaration. The (2) solution has the additional problem of not being able to use the more efficient make_shared.
My question: is there a better way of doing this?
template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(args...);
//return std::shared_ptr<T>(new T(args...)); (2)
}
};
class Foo : public BaseObject<Foo>
{
//friend BaseObject<Foo>; (2)
protected: //public (1)
Foo(int a = 0) : m_foo(a) {}
private:
int m_foo;
};
int main(int argc, char* argv[])
{
Foo::SharedPtr bla = Foo::create(1);
return 0;
}
Update:
They pass-key idiom seems to provide the best solution for me at this moment:
template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
class Key
{
friend class BaseObject<T>;
Key() {}
};
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(Key(), args...);
}
};
class Foo : public BaseObject<Foo>
{
public:
Foo(BaseObject<Foo>::Key, int a = 0) : m_foo(a) {}
private:
int m_foo;
};
The good things:
Only possible to create an object of Foo as a shared_ptr through
Foo::create.
No need to add complex friend declarations in Foo.
std::make_shared still works.
The only problem with this solution is the requirement to have 'Key' as a first argument in the constructor. But I can live with that.
Better is subjective, but I believe it would be a little more intuitive if you would make your constructor private, and std::make_shared a friend function. This way the only function that could create your object would be std::make_shared, and you could write
std::shared_ptr<Foo> ptr = std::make_shared<Foo>(12);
instead of:
Foo::SharedPtr bla = Foo::create(1);
So any future reader of your code would understand what you mean withou actually looking at the Foo class.
UPDATE
I have tried out what I wrote, but did not really work. Here is an answer for a similar question instead, which most likely also aplies for your question:
Using make_shared with a protected constructor + abstract interface
UPDATE 2
Here is how you can make it work (VC++2013)
#include <memory>
using namespace std;
class Foo
{
protected:
Foo(int a = 0) : m_foo(a) {}
private:
int m_foo;
friend shared_ptr<Foo> make_shared<>();
friend class _Ref_count_obj<Foo>;
};
int main()
{
shared_ptr<Foo> foo = make_shared<Foo, int>(12);
return 0;
}
_Ref_count_obj is internally used by make_shared, that's why you need to befriend that too.
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.
I have the following objects
#include <stdio.h>
class foo_t{ };
class bar_t: public foo_t{ };
class zoo_t: public bar_t{ };
class base_t{
public:
void dostuff(foo_t * foo){ printf("Defaulting to base\n"); };
};
class derived_t: public base_t{
public:
void dostuff(bar_t * bar){ printf("Overloading with derived\n"); };
};
int main(){
derived_t derived;
zoo_t zoo;
derived.dostuff(&zoo);
}
I see it is doing what I mean, but I would like you to confirm that this is not just a coincidence.
What I mean is that I want C++ to resolve the method that "gets closer" to the specialized class zoo_t. In this case the first ancestor found is bar_t which determines that the derived_t class method is invoked. Is this the way C++ resolves overloaded methods when arguments are both specialized and base classes?
First off, I see your functions are not virtual. I will assume that's intended and leave virtual out of discussion.
You normally don't overload a base class's member functions in a derived class; you hide them instead. Which means that base_t::dostuff is not accessible through an object-accessing expression of type derived_t. In other words, this won't compile:
int main()
{
derived_t derived;
foo_t foo;
derived.dostuff(&foo);
}
However, this will:
int main()
{
derived_t derived;
foo_t foo;
base_t& base = derived;
base.dostuff(&foo);
derived.base_t::dostuff(&foo);
}
This has other implications as well. For example the code below will print Defaulting to base:
int main()
{
derived_t derived;
zoo_t zoo;
base_t& base = derived;
base.dostuff(&zoo);
}
To summarize - which function gets called is based on the type of the expression choosing the object (the expression to the left of . or ->), and that type only. That will always work that way, so if that's the behaviour you're after, you're fine.
If you want to really overload the inherited function instead of hiding it, you can use a using declaration:
class derived_t: public base_t{
public:
void dostuff(bar_t * bar){ printf("Overloading with derived\n"); };
using bas_t::dostuff;
};
Then, the following code will work:
int main()
{
derived_t derived;
foo_t foo;
bar_t bar;
zoo_t zoo;
derived.dostuff(&foo); // calls base
derived.dostuff(&bar); // calls derived
derived.dostuff(&zoo); // calss derived
}
Live example