While reading this question, I found a strange point:
template <typename T>
class Subclass : public Baseclass<T>
{
public:
using typename Baseclass<T>::Baseclass;
// ^^^^^^^^
};
Since typename
, Baseclass<T>::Baseclass
should be injected class name, not a constructor. As far as I know, it's the same case as this:
template <typename T>
class Base
{
public:
typedef short some_type;
};
template <typename T>
class Sub : public Base<T>
{
public:
using typename Base<T>::some_type;
};
To make sure, I wrote a test code.
#include <iostream>
template <typename T>
class Base
{
public:
Base() { std::cout << "A::A()\n"; }
Base(int) { std::cout << "A::A(int)\n"; }
Base(const char *) { std::cout << "A::A(const char *)\n"; }
};
template <typename T>
class Sub : public Base<T>
{
using typename Base<T>::Base;
};
int main()
{
Sub<char> s1;
Sub<char> s2(3);
Sub<char> s3("asdf");
}
However, it runs on gcc 4.8.3.
$ g++ -std=c++1y -Wall -Wextra -Werror -pedantic test.cpp -o test && ./test
A::A()
A::A(int)
A::A(const char *)
It also runs without typename
.
$ cat test.cpp
...
using Base<T>::Base;
...
$ g++ -std=c++1y -Wall -Wextra -Werror -pedantic test.cpp -o test && ./test
A::A()
A::A(int)
A::A(const char *)
Why did I get these results? What did I miss?
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.
Constructors are not inherited. The superclass constructor can be called from the first line of a subclass constructor by using the keyword super and passing appropriate parameters to set the private instance variables of the superclass.
The obvious reason is that a using declaration and a using directive have different effects. A using declaration introduces the name immediately into the current scope, so using std::swap introduces the name into the local scope; lookup stops here, and the only symbol you find is std::swap .
For multiple inheritance order of constructor call is, the base class's constructors are called in the order of inheritance and then the derived class's constructor.
The standard is pretty clear about this ([namespace.udecl]/1)
using-declaration:
using typename_opt nested-name-specifier unqualified-id ;
The typename
keyword is therefore an optional part of a using declaration that may appear even for using declarations of non-types. The following code should therefore be standard conformant:
template < typename T > class Base {
protected:
typedef T Ttype;
Ttype member;
public:
Base() {
std::cout << "A::A()\n";
}
Base(int) {
std::cout << "A::A(int)\n";
}
Base(const char *) {
std::cout << "A::A(const char *)\n";
}
protected:
void memfunc(void) {
std::cout << "A::memfunc(void)\n";
}
};
template< typename T >
struct SubNoTypename : protected Base< T > {
using Base< T >::Base;
using Base< T >::member;
using Base< T >::memfunc;
using Base< T >::Ttype; // n.b. no error in clang++
};
template< typename T >
struct SubTypename : protected Base< T > {
using typename Base< T >::Base; // error in clang++
using typename Base< T >::member; // error in clang++
using typename Base< T >::memfunc; // error in clang++
using typename Base< T >::Ttype;
};
Both SubNoTypename
and SubTypename
are recognized as standard conformant by gcc. On the other hand clang++ complains in SubTypename
about malplaced typename
keywords. However, this is not even consistent, because it should then complain about a missing typename
in using Base< T >::Ttype;
. This clearly is a clang bug.
Edit
The typename
keyword is also allowed if the base class is no template class, a place where ordinarily you would never expect this keyword to be valid:
class BaseNoTemplate {
protected:
typedef T Ttype;
Ttype member;
public:
BaseNoTemplate() {
std::cout << "A::A()\n";
}
BaseNoTemplate(const char *) {
std::cout << "A::A(const char *)\n";
}
void memfunc(void) {
std::cout << "A::memfunc(void)\n";
}
};
struct SubNoTemplateNoTypename : protected BaseNoTemplate {
using BaseNoTemplate::BaseNoTemplate;
using BaseNoTemplate::member;
using BaseNoTemplate::memfunc;
using BaseNoTemplate::Ttype;
};
struct SubNoTemplateTypename : protected BaseNoTemplate {
using typename BaseNoTemplate::BaseNoTemplate; // error in clang++
using typename BaseNoTemplate::member; // error in clang++
using typename BaseNoTemplate::memfunc; // error in clang++
using typename BaseNoTemplate::Ttype; // n.b. no error in clang++
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With