Trying to allow make_unique on a class with private ctor I came into the following strange difference between two cases:
Case 1 - empty ctor - compiles
class A {
int _i;
A(): _i(7) {}
public:
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
struct enablePrivateCtor : public A {
using A::A;
};
return std::make_unique<enablePrivateCtor>(std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
int main() {
auto a = A::create();
a->doIt();
}
Output:
7
Case 2 - non-empty ctor - doesn't compile
class A {
int _i;
A(int i): _i(i) {} // <- change 1, ctor getting int
public:
// no change here!
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
struct enablePrivateCtor : public A {
using A::A;
};
return std::make_unique<enablePrivateCtor>(std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
int main() {
auto a = A::create(7); // <- change 2, sending 7
a->doIt();
}
Compilation Error:
unique_ptr.h: error: calling a private constructor of class 'enablePrivateCtor'
Why the 1st one - with the empty ctor - is OK, while the 2nd - the non-empty ctor - is not?
The default constructor is never inherited. Therefore, the first enablePrivateCtor generates a default constructor, which calls the base class default constructor.
When you inherit a constructor (as in the second case), the new constructor has the same access level as the inherited one. So since A::A(int) is private, so too will be enablePrivateCtor::enablePrivateCtor(int). So you won't be able to construct with it.
If you need to have a private constructor be able to be called indirectly (through make_unique/emplace/etc), then you need to use a private key type. Like this:
class A;
class A_key
{
A_key() = default;
A_key(int) {} //Prevent `A_key` from being an aggregate.
friend class A;
};
class A {
int _i;
public:
A(int i, A_key): _i(i) {}
// no change here!
template<typename... T>
static std::unique_ptr<A> create(T&&... t)
{
return std::make_unique<A>(std::forward<T>(t)..., A_key{});
}
void doIt() const {
std::cout << _i << std::endl;
}
};
...
auto ptr = A::create(7);
A a(7, A_key{}); //Does not compile, since you're not a friend.
A_key is publicly copyable, but it is not publicly default constructible. So non-private code can pass them around, but non-private code cannot create them.
The difference is that enablePrivateCtor automatically gets a default constructor (which is allowed to call A::A).
It doesn't automatically get an integer conversion constructor: add
enablePrivateCtor(int i) : A(i) {}
and see it work.
The code you posted has undefined behavior.
In particular, you allocate an enablePrivateCtor then delete an A.
A better way than this is to use a key type.
class A {
int _i;
A(): _i(7) {}
class construction_token_t {
explicit construction_token_t(int) {}
friend class A;
};
static auto ctor_token() {
return construction_token_t(0);
}
public:
template<class...Args>
A( construction_token_t, Args&&...args ):A(std::forward<Args>(args)...){}
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
return std::make_unique<A>(ctor_token(), std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
We create a token which can grant another class the right to access our private ctor. The only one who can create this token is our class.
We then pass it to make_unique.
An alternative is to use the factory lambda pattern.
template<class F>
struct factory_lambda_t {
F f;
template<class T>
operator T() const { return f(); }
};
template<class F>
factory_lambda_t<std::decay_t<F>>
factory( F&& f ) { return {std::forward<F>(f)}; }
In C++14 this requires move/copy ctors to be public, but in C++17 it doesn't.
class A {
int _i;
A(): _i(7) {}
public:
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
return std::make_unique<A>(factory([&]{
return A(std::forward<T>(t)...);
}));
}
void doIt() const {
std::cout << _i << std::endl;
}
};
which I think is pretty slick.
This may result in eliding constructors completely in some cases. In others, a single move occurs.
Related
I'm trying to implement a sort of static polymorphism by means of the CRTP and requires clauses.
What I want to achieve is to call a possibly overriden function in a function taking a reference to the CRTP base class.
I made it work with GCC 10 and 11 with the following approach:
#include <iostream>
template<typename T>
class Base
{
public:
void f() const requires T::IsOverridden
{ static_cast<T const *>(this)->f(); }
void f() const
{ std::cout << "Fallback f()" << std::endl; }
};
class A : public Base<A>
{
public:
static constexpr bool IsOverridden = true;
public:
void f() const
{ std::cout << "Overridden f()" << std::endl; }
};
class B : public Base<B> {};
template<typename T>
void f(Base<T> const &x)
{ x.f(); }
int main()
{
A const a;
B const b;
f(a);
f(b);
return 0;
}
However, Clang 11 doesn't like this piece of Code:
test.cpp:7:30: error: no member named 'IsOverridden' in 'A'
void f() const requires T::IsOverridden
~~~^
test.cpp:14:18: note: in instantiation of template class 'Base<A>' requested here
class A : public Base<A>
^
test.cpp:7:30: error: no member named 'IsOverridden' in 'B'
void f() const requires T::IsOverridden
~~~^
test.cpp:24:18: note: in instantiation of template class 'Base<B>' requested here
class B : public Base<B> {};
^
Which compiler is right?
Note: I'm using a boolean member to signal overriding because I want it to work with classes nested in template classes and that was the only way I came up with in that case.
I'm posting what I ended up using in case it is useful for somebody else.
I didn't like using a member variable, which I could easily misspell, to signal that the function was overridden.
Instead I used a defaulted std::false_type NTTP for the base-class function, and a std::true_type NTTP for the overloads, so that they can be detected with a requires-expression:
#include <iostream>
#include <type_traits>
template<typename T>
class Base
{
public:
template<std::false_type = std::false_type{}>
requires requires(T const x) { x.template f<std::true_type{}>(); }
void f() const
{ static_cast<T const *>(this)->f(); }
template<std::false_type = std::false_type{}>
void f() const
{ std::cout << "Fallback f()" << std::endl; }
};
class A : public Base<A>
{
public:
template<std::true_type = std::true_type{}>
void f() const
{ std::cout << "Overridden f()" << std::endl; }
};
class B : public Base<B> {};
template<typename T>
void f(Base<T> const &x)
{ x.f(); }
int main()
{
A const a;
B const b;
f(a);
f(b);
return 0;
}
GCC 11 accepts the terser syntax template<std::true_type = {}>, but GCC 10 and CLang 12 require the longer template<std::true_type = std::true_type{}>.
Defining the classes A with private constructor and destructor (it should be so!) and B as a friend class, how can I creat a vector of A objects in B and fill it with the function addA(). I got the error "error C2248: "A::~A": No access to private members whose declaration was made in the A class".
class A
{
private:
A();
A(const std::string& name, const float& num);
~A();
public:
friend class B;
private:
std::string name_;
float num_;
};
A::A()
{
name_ = "NoName";
num_ = 0.0;
}
A::A(const std::string& name, const float& num)
{
name_ = name;
num_ = num;
}
A::~A()
{
}
class B
{
public:
B();
~B();
void addA(const std::string name, const float num);
private:
vector<A> vecA;
};
B::B()
{
}
B::~B()
{
}
void B::addA(const std::string name, const float num)
{
A a(name, num);
vecA.push_back(a);
}
int main()
{
B b;
b.addA("Name", 1.0);
return 0;
}
While #Fureeish has a neat solution, here's a slightly simpler alternative: just wrap it.
class AccessPrivate;
class PrivStuff
{
private:
PrivStuff() {}
~PrivStuff() {}
public:
friend class AccessPrivate;
std::string m_data{};
};
class AccessPrivate
{
public:
AccessPrivate() = default;
~AccessPrivate() = default;
PrivStuff m_priv;
};
int main(int argc, char* argv[])
{
std::vector<AccessPrivate> myvec;
myvec.resize(4);
for (auto& stuff : myvec)
{
stuff.m_priv.m_data = "heya";
}
}
If you need something more complicated, like passing in arguments, just add an equivalent constructor to AccessPrivate and there you go. You can essentially treat AccessPrivate almost like the actual private class, just one level of indirection.
how can I create a vector of A objects in B [...] ?
You can't do that. While B is a friend of A, std::vector is not a friend of A, which means that it cannot access private members of A, e.g., constructor, which is required for a vector to work.
However, if you are okay with a little indirection, little potential performance hit and a change in your signature, you can replace the not-working std::vector<A> with a workig std::vector<std::unique_ptr<A, deleter>>.
It's important to note that plain std::unique_ptr will not work here. It has a similar problem to std::vector - it cannot access private destructor of A. One way to work around it is to outsource the job of constructing and destructing of As entirely to B - via explicit construction and destruction, that is:
new A(name, num)
static void deleter_a(A* a) { delete a; }
in B's scope.
Now we can do:
std::vector<std::unique_ptr<A, std::function<void(A*)>>> vecA;
instead of: std::vector<A> or std::vector<std::unique_ptr<A>>. This is important - neither std::unique_ptr nor std::vector construct or destruct your As. B is entirely responsible for constructing (new A(name, num)) and destructing (static void deleter_a(A* a) { delete a; }) As.
Full B class:
class B {
public:
B() {}; // or = default
~B() {}; // or = default
void addA(const std::string name, const float num);
private:
static void deleter_a(A* a) { delete a; }
using deleter_a_t = void(A*);
std::vector<std::unique_ptr<A, std::function<deleter_a_t>>> vecA;
};
void B::addA(const std::string name, const float num) {
vecA.push_back(std::unique_ptr<A, std::function<deleter_a_t>>{
new A(name, num), std::function<deleter_a_t>{deleter_a}
});
}
Contrary to what the other answers say, it is possible to do this without any extra indirection.
std::vector doesn't directly call the constructor and the destructor, but uses an allocator. If you want an std::vector to manage A objects, you just need to provide it an allocator that implements the construct and destroy functions, and that is either a friend of A or a nested class of B (since B is already a friend of A).
Example:
#include <memory>
#include <utility>
#include <vector>
class A {
A() = default;
~A() = default;
friend class B;
};
class B {
template<typename T>
struct custom_alloc : std::allocator<T> {
template<typename U, typename... Args>
void construct(U* p, Args&&... args){
::new(const_cast<void*>(static_cast<const volatile void*>(p))) U(std::forward<Args>(args)...);
}
template<typename U>
void destroy(U* p){
if constexpr (std::is_array_v<U>){
for(auto& elem : *p){
(destroy)(std::addressof(elem));
}
} else {
p->~U();
}
}
};
public:
std::vector<A,custom_alloc<A>> vec;
void new_A(){
vec.push_back(A());
}
};
For the implementation of construct and destroy, I used an equivalent implementation of the c++20 versions of std::destroy_at and std::construct_at. I suspect that destroy is overkill and just a call to the destructor would be sufficient, but I'm not sure.
I want to have something like that:
template<class... Args>
class MyClass : public Args
{
MyClass<class... Args>(/*some parameters*/)
{ }
}
// ana then:
MyClass<Base1, Base2, Base3>(/*some arguments*/)
That i want to dynamic_cast to Base1 or etc. and to use his methods.
I know that this code will not work, but do you have any ideas how to do it?
This works fine:
struct Base1
{};
struct Base2
{};
struct Base3
{};
template<class... Args>
struct MyClass : public Args...
{};
MyClass<Base1, Base2, Base3> mc;
There is no need for the <> in your constructor, you are missing "..." after public Args and you are missing a ";" at the end of your class definition.
I know that this code will not work, but do you have any ideas how to do it?
To make it works you have to
(1) add the ellipsis (...) inheriting Args...
class MyClass : public Args...
// ........................^^^
(2) make MyClass a struct or make public the constructor
(3) remove the <class... Args> part defining the constructor (it's implicit)
(4) add some as follows
Args const & ... as
for constructor arguments
(5) add a semicolon closing the class or struct
Now the following code works
struct Base1 {};
struct Base2 {};
struct Base3 {};
template<class... Args>
struct MyClass : public Args...
{
MyClass (Args const & ...)
{ }
};
int main()
{
MyClass<Base1, Base2, Base3>(Base1{}, Base2{}, Base3{});
MyClass(Base1{}, Base2{}, Base3{}); // C++17 only
}
Observe the last line in main()
MyClass(Base1{}, Base2{}, Base3{}); // C++17 only
Works only from C++17 because uses a new C++17: deduction guides.
In your case, there is an implicit deduction guides that permit to deduce the template types of the class from the types of the argument passed to the constructor.
Another example of use (more useful?) could be
MyClass mc{ Base1{}, Base2{}, Base3{} };
At very first, you are using invalid syntax. When using variadic templates, you need to 'unpack' them (correct term: 'expand the parameter pack') when using them:
template<typename... Args>
class MyClass : public Args ...
// ^^^
{ };
In the constructor, you can skip the template parameters entirely, but if you specify them, you need to 'unpack' them again:
MyClass<Args ...>(/*some parameters*/);
// ^^^^^^^^^^ optional
Once the class is defined, you can specify the template arguments just as with classic templates, solely that the number can differ:
MyClass<Base1> c1;
MyClass<Base1, Base2> c2;
MyClass<Base1, Base2, Base3> c3;
Since C++17 and with appropriate constructor, you can even let the class template arguments get deduced:
template<typename... Args>
class MyClass : public Args ...
{
public:
MyClass(Args const&... args)
: Args(args)... // call base class copy constructors!
// (note the unpacking again)
{ }
MyClass(Args&&... args)
: Args(std::forward(args))... // call base class move constructors!
// (note the unpacking again)
{ }
};
MyClass c0;
MyClass c1(Base1());
MyClass C2(Base1(), Base2());
std::cout << std::is_same_v<decltype(c0), MyClass<>> << std::endl;
std::cout << std::is_same_v<decltype(c1), MyClass<Base1>> << std::endl;
std::cout << std::is_same_v<decltype(c2), MyClass<Base1, Base2>> << std::endl;
Note that inheritance is a red herring here, that works without as well. See class template argument deduction.
Let me show you some working example as you requested:
#include<iostream>
class B1 {
private:
int *m;
public:
B1() { m = new int;}
~B1() { delete m;}
void SetM(int a) { *m = a;}
int GetM() { return *m;}
};
class B2 {
private:
std::string str;
public:
B2() { str = "";}
~B2() {}
void SetStr(std::string a) { str = a;}
std::string GetStr() { return str;}
};
class B3 {
private:
float f;
public:
B3() { f = 0.0 ;}
~B3() {}
void SetF(float a) { f = a;}
float GetF() { return f;}
};
template<class... Args>
class MyClass : public Args... {
};
int main () {
MyClass<B1,B2,B3> l;
l.SetM(1);
if (auto a = dynamic_cast<B1*>(&l)) {
std::cout<<" " << a->GetM() <<"\n";
} else {
std::cout<<"ERROR:\n";
}
}
Hope this helps,
Thanks,
Rajkumar
Is it possible to pass this by default ?
Here is what I currently have
class A
{
public:
template<typename T>
void dowithT(T t) {}
};
class B
{
public:
A a;
B()
{
//Calling 'dowithT' with 'this'
a.dowithT(this);
}
};
This function requires passing this from the caller of the function every time. So I wondered if there is a way to encapsulate this task, so that you don't need to pass this to dowithT.
I tried to do something like this:
class A
{
public:
// '= this' doesn't compile
template<typename T>
void dowithT(T t = this) {}
};
class B
{
public:
A a;
B()
{
//Calling 'dowithT' without 'this'
a.dowithT();
}
};
Unfortunately, I can't use templates, so my first solution isn't an option.
Is this possible?
Edit: I gave a concrete answer with my own implementation below. Also with a few mor deatils of what I wanted in the end.
TL;DR No, this is not possible.
this is not the same type in every class, you can't generalize it, so no, not possible.
Additionally, what would this be if doWithT() was called from a non-member function? nullptr?
That's why it isn't possible. You have to use a template.
Instead of B having a member of type A, it can inherit from A, and use something like the "curiously recurring template pattern."
If you cannot make class A a template, you can still do it like so:
class A
{
protected:
template <class T>
void dowithT()
{
T* callerthis = static_cast<T*>(this);
// callerthis is the "this" pointer for the inheriting object
cout << "Foo";
}
};
class B : public A
{
public:
B()
{
dowithT<B>();
// Or A::dowithT<B>();
}
};
dowithT() must only be called by an inheriting class (hence I made it protected), with the template parameter the caller's own type, or you'll break everything.
You may achieve exactly what you want by using a private mixin class to provide the dowithT method that takes no arguments:
#include <iostream>
#include <typeinfo>
class A
{
public:
template<typename T>
void dowithT(T* t) {
std::cout << "Hello, World" << typeid(*t).name() << std::endl;
}
};
template<class Owner>
struct calls_a
{
void dowithT()
{
auto p = static_cast<Owner*>(this);
p->a.dowithT(p);
}
};
class B
: private calls_a<B>
{
friend calls_a<B>;
A a;
public:
B()
{
//Calling 'dowithT' with 'this'
dowithT();
}
};
int main()
{
B b;
}
No, it is not possible. There is nothing really special about this when used as an argument to a function taking T* (template or not), it's just a pointer like any other.
this A is different from this B. In your first code, this refers to the caller, while in the second this refers to the callee. Thus what you want to do isnt really possible.
Here's one possibility, which might, or might not suit your needs:
template<typename T>
class A
{
public:
A(T t) : t(t) {}
void dowithT()
{
cout << "Foo";
}
private:
T t;
};
class B
{
public:
A<B*> a;
B() : a(this)
{
a.dowithT();
}
};
You could use a private method in class B that acts as a relay, and use the constant nullptr as a special value for this, if you want to be able to pass other values:
class B
{
public:
A a;
B()
{
//Calling 'dowithT' with 'this'
innerdo();
}
private:
void innerdo(B *p = nullptr) {
if (p == nullptr) p = this;
a.dowithT(p);
}
};
If you only need to pass this it is even simpler
void innerdo() {
a.dowithT(this);
}
After trying out various things you mentioned, I'd like to give my answer/solution to the problem myself to clarify some details:
#include <iostream>
using namespace std;
#include <functional>
template <typename CallerType>
class AFunctionConstructor{
private:
virtual void abstr()
{}
public:
typedef void(CallerType::*CallerTypeFunc)();
function<void()>* constructFunction(CallerTypeFunc func)
{
CallerType* newMe = dynamic_cast<CallerType*> (this);
return new function<void()>(std::bind(func,newMe));
}
};
class A : public function<void()>
{
protected:
public:
A();
A(function<void()>* func) : function<void()>(*func)
{}
};
// now create ressource classes
// they provide functions to be called via an object of class A
class B : public AFunctionConstructor<B>
{
void foo()
{
cout << "Foo";
}
public:
A a;
B() : a(constructFunction(&B::foo)) {}
};
class C : public AFunctionConstructor < C >
{
void bar()
{
cout << "Bar";
}
public:
A a;
C() : a(constructFunction(&C::bar)) {}
};
int main()
{
B b;
C c;
b.a();
c.a();
cout << endl;
A* array[5];
array[0] = &b.a; //different functions with their ressources
array[1] = &c.a;
array[2] = &b.a;
array[3] = &c.a;
array[4] = &c.a;
for (int i = 0; i < 5; i++) //this usability i wanted to provide
{
(*(array[i]))();
}
getchar();
return 0;
}
Output :
FooBar
FooBarFooBarBar
This is as far as i can press it down concerning examples. But i guess this is unsafe code. I stumbled across possible other and simpler ways to achieve this (other uses of std::function and lambdas(which i might have tried to reinvent here partially it seems)).
At first I had tried to pass "this" to the bind function in function<void()>*AFunctionConstructor::constructFunction(CallerTypeFunc func)
,though, which i now get through the dynamic upcast.
Additionally the functionality of AFunctionConstructor was first supposed to be implemented in a Constructor of A.
How can I achieve the following design using C++11:
class Consumer : Base<Consumer>
{
// different consumers will have different methods (of the same signature)
void Foo(){...}
void Bar(){...}
: // etc.
static void override
register_all () {
register_method<&Consumer::Foo>("foo");
register_method<&Consumer::Bar>("bar");
: // etc.
}
:
}
template<typename T>
class Base
{
static
Base() {
register();
}
virtual static void
register_all(){ };
using F = void(T::*)();
template<F f>
static void
register_method(std::string name) {
...
}
}
...?
Note that I'm doing two illegal things:
I am using a static constructor (not allowed) on the base class
I am using virtual static function (also not allowed)
NOTE: Registration of methods needs to occur only once, before the first instance is accessed (it will populate a static C-function-pointer table).
Finally, is there any better technique I could be using, some way of somehow tagging or marking methods that need to be registered, and save the consumer the trouble of having to manually register them in a separate function?
I believe regular CRTP will work just fine. This gets rid of both the virtual and the static. Using an std::once_flag in combination with std::call_once will allow you to only call the function once -- mimicking the effects of a 'static constructor'. It just requires a little bit of messing around.
Full Code:
#include <iostream>
#include <mutex>
template<typename T>
struct Base {
Base() {
static_cast<T*>(this)->register_all();
}
using F = void(T::*)();
template<F f>
void register_method(const char* str) {
// ...
std::cout << "registered " << str << '\n';
}
};
struct Derived : Base<Derived> {
private:
static std::once_flag flag_;
void implementation() {
register_method<&Derived::foo>("foo");
register_method<&Derived::bar>("bar");
}
public:
void foo() {}
void bar() {}
void register_all() {
std::call_once(flag_, [this]{ implementation(); });
}
};
std::once_flag Derived::flag_;
int main() {
Derived x;
Derived y;
}
Live Demo
I've modified Rapptz's answer to move all the machinery back into the base class:
http://coliru.stacked-crooked.com/a/52fd723e905333c6
#include <iostream>
#include <mutex>
template<typename T>
struct Base {
Base() {
std::call_once(flag_, T::register_all );
}
using F = void(T::*)();
template<F f>
static void register_method(const char* str) {
// ...
std::cout << "registered " << str << '\n';
}
public:
static std::once_flag flag_;
};
// have to initialise static-s outside class...
template<typename T>
std::once_flag Base<T>::flag_{};
...
struct Derived1 : Base<Derived1> {
public:
static void register_all() {
std::cout << "D1" << '\n';
register_method<&Derived1::foo>("foo");
register_method<&Derived1::bar>("bar");
}
public:
void foo() {}
void bar() {}
};
struct Derived2 : Base<Derived2> {
public:
static void register_all() {
std::cout << "D2" << '\n';
register_method<&Derived2::woot>("woot");
}
public:
void woot() {}
};
...
int main() {
Derived1 x;
Derived1 y;
Derived2 z;
}
EDIT: strangely I need to initialise my flag with {} but Rapptz didn't. Why is this?
EDIT2: this code fails on ideone, because ideone doesn't use -pthread compiler flag. Using a simpler 'static bool first=true; if(first){first = false;...} construct would do the trick as c++11 stipulates that initialisation of static variables be thread safe.