Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inheriting constructors vs forwarding

C++11 allows inheriting constructors making it possible to avoid a lot of boilerplate, especially with something like a wrapper class. However, it seems like you could already achieve this functionality with variadic templates alone.

class B
{
public:
 B(int){//do something}
 B(int, char){//do something}
};

Using inheriting constructors:

class D : public B
{
public:
 using B::B; 
};

Using variadic templates and forward:

class D : public B
{
public:
 template <typename...Args>
 D(Args&&... args) : B(std::forward<Args>(args)...)
 {
 }
};

While consistency(treat constructors and methods the same way for using) and ease of use are very good reasons to bring inherited constructors into the language, is there any other reason why the first solution should be preferred to the second? Both the CWG documents(N1890 and N1898) I found discussing inheriting constructors simply note the following and move on:

Little more than a historical accident prevents using this to work for a constructor as well as for an ordinary member function. Had a constructor been called “ctor” or “constructor” rather than being referred to by the name of their class, this would have worked. We propose this as the mechanism for inheriting constructors.

like image 722
Pradhan Avatar asked Jan 09 '23 02:01

Pradhan


2 Answers

The big reason is that perfect forwarding isn't perfect. Simple case:

struct B {
    B(int* ) { .. }
};

Now consider:

D d{0};

If we inherit the constructor, this works fine. If we perfect-forward, we would try to construct B(int ), since 0 deduces as int, which is a constructor that doesn't exist. Failure!

Other failure cases include braced initialization, declaration-only static const data members, overloaded functions, and bitfields.

like image 172
Barry Avatar answered Jan 15 '23 15:01

Barry


Perfect forwarding isn't quite perfect. In particular, 0 as actual argument reduces to int instead of denoting a general nullvalue. So with a constructor taking a pointer argument, 0 will work as actual argument for an inherited constructor, but not for the forwarding.

Another reason that I think I mentioned at one time when the question (do we really need inheriting constructors) was aired, is that inheriting constructors is a simple notation for a conceptually simple thing, to be used in the context of a simple class. There is enough forced complexity and forced boilerplate in C++.

like image 27
Cheers and hth. - Alf Avatar answered Jan 15 '23 16:01

Cheers and hth. - Alf