Deleted constructor and template - c++

Consider the following:
template<typename T>
class A
{
public:
A(int a)
{}
A() = delete;
};
class B
{
public:
B()
{
A<int> a;
}
};
Of course this code does not compile because class B's constructor is attempting to default-construct a class A object and I've explicitly deleted that constructor. All well and good.
However, if I make B a class template
template<typename T>
class A
{
public:
A(int a)
{}
A() = delete;
};
template<typename T>
class B
{
public:
B()
{
A<int> a;
}
};
then the code does compile and it seems I can now default-construct an instance of class A.
Why is this? What am I missing?
Thanks.

D'oh! It appears that the compiler doesn't see the error until it attempts to instantiate a class from the template.
Actually trying to create an object of type B<> generates the expected error.
Sorry if I wasted your time.

Related

C++ Cannot construct class that extends template [duplicate]

Why does this code:
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
};
int main(void)
{
B *b = new B(5);
delete b;
}
Result in these errors:
main.cpp: In function ‘int main()’:
main.cpp:13: error: no matching function for call to ‘B::B(int)’
main.cpp:8: note: candidates are: B::B()
main.cpp:8: note: B::B(const B&)
Shouldn't B inherit A's constructor?
(this is using gcc)
If your compiler supports C++11 standard, there is a constructor inheritance using using (pun intended). For more see Wikipedia C++11 article. You write:
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
using A::A;
};
This is all or nothing - you cannot inherit only some constructors, if you write this, you inherit all of them. To inherit only selected ones you need to write the individual constructors manually and call the base constructor as needed from them.
Historically constructors could not be inherited in the C++03 standard. You needed to inherit them manually one by one by calling base implementation on your own.
For templated base classes, refer to this example:
using std::vector;
template<class T>
class my_vector : public vector<T> {
public:
using vector<T>::vector; ///Takes all vector's constructors
/* */
};
Constructors are not inherited. They are called implicitly or explicitly by the child constructor.
The compiler creates a default constructor (one with no arguments) and a default copy constructor (one with an argument which is a reference to the same type). But if you want a constructor that will accept an int, you have to define it explicitly.
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
public:
explicit B(int x) : A(x) { }
};
UPDATE: In C++11, constructors can be inherited. See Suma's answer for details.
This is straight from Bjarne Stroustrup's page:
If you so choose, you can still shoot yourself in the foot by inheriting constructors in a derived class in which you define new member variables needing initialization:
struct B1 {
B1(int) { }
};
struct D1 : B1 {
using B1::B1; // implicitly declares D1(int)
int x;
};
void test()
{
D1 d(6); // Oops: d.x is not initialized
D1 e; // error: D1 has no default constructor
}
note that using another great C++11 feature (member initialization):
int x = 77;
instead of
int x;
would solve the issue
You have to explicitly define the constructor in B and explicitly call the constructor for the parent.
B(int x) : A(x) { }
or
B() : A(5) { }
How about using a template function to bind all constructors?
template <class... T> Derived(T... t) : Base(t...) {}
Correct Code is
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
public:
B(int a):A(a){
}
};
main()
{
B *b = new B(5);
delete b;
}
Error is b/c Class B has not parameter constructor and second it should have base class initializer to call the constructor of Base Class parameter constructor
Here is how I make the derived classes "inherit" all the parent's constructors. I find this is the most straightforward way, since it simply passes all the arguments to the constructor of the parent class.
class Derived : public Parent {
public:
template <typename... Args>
Derived(Args&&... args) : Parent(std::forward<Args>(args)...)
{
}
};
Or if you would like to have a nice macro:
#define PARENT_CONSTRUCTOR(DERIVED, PARENT) \
template<typename... Args> \
DERIVED(Args&&... args) : PARENT(std::forward<Args>(args)...)
class Derived : public Parent
{
public:
PARENT_CONSTRUCTOR(Derived, Parent)
{
}
};
derived class inherits all the members(fields and methods) of the base class, but derived class cannot inherit the constructor of the base class because the constructors are not the members of the class. Instead of inheriting the constructors by the derived class, it only allowed to invoke the constructor of the base class
class A
{
public:
explicit A(int x) {}
};
class B: public A
{
B(int x):A(x);
};
int main(void)
{
B *b = new B(5);
delete b;
}

How to enforce implementing the constructor of a specific data type on a derived class?

Given an abstract class A and a data type T, is there a way to enforce implementing a constructor of T on a derived class of A? i.e.
class A {
public:
virtual ~A() {}
virtual void foo() = 0;
};
class B : public A {
public:
B(T t) { ... } // this constructor must be implemented otherwise compilation will error out
};
It is possible with a private token based design. This idea looks something like the following:
#include <utility>
#include <memory>
class A{
private:
struct create_token
{
create_token(const create_token &) = delete;
create_token& operator=(const create_token &) = delete;
create_token(create_token &&) = default;
create_token& operator=(create_token &&) = default;
friend class A;
private:
create_token(){};
};
inline static auto token = create_token{};
protected:
A(create_token) {}
public:
template<class T, typename... ARGUMENTS>
static std::unique_ptr<T> create(ARGUMENTS&&... arguments)
{
// Whatever creation mechanism here
return std::make_unique<T>(create_token{}, std::forward<ARGUMENTS>(arguments)...);
}
};
class B : public A {
public:
template <typename Token> // Can't name A::create_token, it is private
B(Token tok) : A(std::move(tok)) {}
B(){} // Will always lack a `create_token`
};
The example needs a bit of modification for your case (mainly to restrict the constructor) - but the point is that construction can only go through the factory create function.
If A will have it's own constructor which takes parameter and no default constructor
class A {
public:
A(T t) {};
virtual ~A() {}
virtual void foo() = 0;
};
Then all derived classes have to initialize that in their constructor, which means at least one constructor will be needed.
See below examples:
class B : public A {
public:
B(T t):A(t) { ... } // pass parameter to A constructor
};
class C : public A {
public:
C(): A(T{}) { ... } // initialize A with a default T
};
class D : public A {
public:
using A::A; // inherit A's constructors
};
class E : public A {
public:
//error - doesn't work without any constructor!
};
You shouldn't try to force any constructor syntax in derived classes - they may know things which you don't know and they may or may not need T. I'm not sure if forcing constructor signature is even possible.
My best shot would be using CRTP, so that you can check the properties of the derived class within the base class:
template <class Derived>
class A_CRTP //: public A_Base
{
protected:
A() {
static_assert(sizeof(Derived{T}) > 0, "Constructor from T not present");
}
};
class B : public A_CRTP<B> {
public:
B();
B(T); // removing this is a compile-time error.
};
However, this is trivially bypassed:
class C : public B
{
C();
// No C(T) needed, B has that and A doesn't know about C.
};
https://godbolt.org/z/qzd_LJ
That makes this whole exercise somewhat pointless, as it just forces users to take extra steps before they can write the set of constructors they want (see answer of #Yksisarvinen).

C++ instantiate class inside a class with ctor parameters

I have a problem with instantiating a class as a member of another class.
Here is my code:
class myClassA{
public:
myClassA(){
printf("myClassTwo ctor");
}
void doSomething(){ printf("myClassA did something\r\n");}
};
class myClassB{
public:
myClassB(int i){
printf("myClassA ctor got %d\r\n",i);
threeMyI = i;
}
private:
int threeMyI;
};
class myClassC{
public:
myClassC(){
printf("C ctor without params\r\n");
}
myClassA instanceA;
myClassB instanceB(29); //<== Not working why??
};
I have a class myClassC which I want to have two members, one of type myClassA and one myClassB. This works well for myClassA. But as soon as I try to create an instance of myClassB, which has an ctor parameter, it fails with the following compiler error:
..\src\main.cpp:34:21: error: expected identifier before numeric constant
myClassB instanceB(29); //<== Not working why??
..\src\main.cpp:34:21: error: expected ',' or '...' before numeric constant
In my main function this type of declaration works well:
int main(void){
printf("class test\r\n");
myClassC instanceC1;
myClassA instanceA1;
myClassB instanceB1(25);
return 0;
}
But I have no idea what makes the big difference when instantiating a class with ctor parameters. Hope somebody can give me an hint what I'm doing wrong.
You can only declare member variables, you cannot instantiate them.
To invoke the constructor of a member-variable you can use the memberwise initialization paradigm in your own constructors:
struct A { // same as class A but public by default
int m_a;
A(int a) : m_a(a) {}
};
struct B {
A m_a;
int m_b;
B(int a, int b) : m_a(a), m_b(b) {}
};
Or using your code:
#include <cstdio>
class myClassA{
public:
myClassA(){
printf("myClassTwo ctor");
}
void doSomething(){ printf("myClassA did something\r\n");}
};
class myClassB{
public:
myClassB(int i) : threeMyI(i) {
printf("myClassA ctor got %d\r\n",i);
}
private:
int threeMyI;
};
class myClassC{
public:
myClassC() : instanceA(), instanceB(20) {
printf("C ctor without params\r\n");
}
myClassA instanceA;
myClassB instanceB;
};
int main()
{
myClassA a;
myClassB b(10);
myClassC c;
}
Live demo
From what I have understand, it seems that you want to use a default instantiation for your private attribute instanceB. In that case, what you are proposing is not legal, default input parameters should be set as followed
myClassC() : instanceB(29) { // mind the ":" character
printf("C ctor without params\r\n");
}
This will have the effect to call the constructor of myClassB to instantiate your private attribute instanceB with relevant default parameter.

Moving Template Method to Derivative Breaks Compilation

Given the following code:
template<typename T>
class A
{
public:
T t;
};
class B
{
public:
void foo(int i) {}
template<typename T>
void foo(A<T>& a) {}
};
int main()
{
A<int> a;
B b;
b.foo(a );
b.foo(a.t);
}
This compiles and works fine; the correct overloaded versions of B::foo() are chosen and called for a and a.t.
Now I introduce a new class C which derives from B and move the template version of ::foo() out of B and into C:
template<typename T>
class A
{
public:
T t;
};
class B
{
public:
void foo(int i) {}
};
class C: public B
{
public:
template<typename T>
void foo(A<T>& a) {}
};
int main()
{
A<int> a;
C c;
c.foo(a ); // Fine
c.foo(a.t); // Error
}
And now the code won't compile anymore. Visual Studio 2005 is stating:
error C2784: 'void C::foo(A<T> &)' : could not deduce template argument for 'A<T> &' from 'int'
In fact, calling C::foo() with any int value results in this error. It almost seems like the method overload for int is being hidden by the template overload.
Why is this happening? Is it some issue with Visual Studio 2005's compiler? Unfortunately, I cannot test it on any other compiler right now.
Any information is appreciated.
It almost seems like the method overload for int is being hidden by the template overload.
Exactly! You need to add a using declaration to class C:
class C: public B
{
public:
using B::foo;
template<typename T>
void foo(A<T>& a) {}
};
When you declare a member function in a derived class, all member functions in the base class with the same name are hidden. See §3.3.10/3 of ISO/IEC 14882:2011:
The declaration of a member in a derived class (Clause 10) hides the declaration of a member of a base class of the same name; see 10.2.
It's hiding, no overloading. Use
class C: public B
{
public:
using B::foo;
template<typename T>
void foo(A<T>& a) {}
};
Correct, the base function is hidden. That's actually the proper term for it. Add using B::foo; to the class definition of C to unhide it.

Allow class access to single private member

I have a class A which has a private method called a(). I have also a class B which needs to access a() (but just B should have access to a(), thats why a() is private). I could now use a friend specifier but that would make other private methods of A (lets call them b() and c()) also available to B and I dont want that behaviour.
Is there a way to make just a() of A accessable to B?
There is a way -- if your class has a public template function:
class A {
// apparently private
void priv () { std::cout << "got you A::a()" << std::endl ; }
public:
template <class T>
void abuse() {}
};
struct Thief {};
template <>
void A::abuse<Thief>() {
this->priv();
}
int main() {
A a;
// obviously do not compile : a.priv();
// this i OK
a.abuse<Thief>();
return 0;
}
I must confess I stole this from GotW...
No there's not, but as you specify the precise class, just B could access A's private members.
You just have to take care of what method are called.
As friend relationship are not inherited, you don't have to worry about B's possible subclasses.
This could be done with some "twist".
Just factor out method a() from A class into a parent class that has B as a friend class, then let A inherit it. this will leave a() as being a method in A, but the only private method accessible by its parent's friend B.
here is a very simple code to clarify what I've said:
class parent
{
friend class B;
private:
void a() {}
};
class A:public parent
{
private:
void b() {}
void c() {}
};
class B
{
A* m_a;
public :
B()
{
m_a = new A();
m_a->a(); // OK
m_a->b(); // error C2248: 'A::b' : cannot access private member declared in class 'A'
}
};
hope it helps !
Yes, I have an easy way. Let B have a pointer of A::a(), like this:
typedef boost::function<void ()> functype;
class A {
private:
void a();
};
class B {
public:
void setfp(functype f) {m_f = f;}
void foo() {
// do some stuff
m_f();
}
private:
functype m_f;
};
A a;
B b;
b.setfp(boost::bind(&A::a, &a));
b.foo();