C++在继承构造函数中使用具有typename的声明
C++ using declaration with typename in inheriting-constructors
在阅读这个问题时,我发现了一个奇怪的点:
template <typename T>
class Subclass : public Baseclass<T>
{
public:
using typename Baseclass<T>::Baseclass;
// ^^^^^^^^
};
由于typename
,Baseclass<T>::Baseclass
应该是注入的类名,而不是构造函数。据我所知,情况与此相同:
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;
};
为了确保安全,我写了一个测试代码。
#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");
}
但是,它在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 *)
它也在没有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 *)
为什么我得到这些结果?我错过了什么?
标准对此非常清楚([namespace.udcl]/1)
使用声明:
使用typename_opt嵌套名称说明符非限定id;
因此,typename
关键字是using声明的可选部分,即使对于非类型的using声明也可能出现该部分。因此,以下代码应符合标准:
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;
};
SubNoTypename
和SubTypename
都被gcc认定为符合标准。另一方面,clang++在SubTypename
中抱怨typename
关键字不正确。然而,这甚至不一致,因为它应该抱怨using Base< T >::Ttype;
中缺少typename
。这显然是一个叮当作响的bug。
编辑如果基类不是模板类,typename
关键字也是允许的,在这个地方通常你永远不会期望这个关键字是有效的:
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++
};
对不起,为什么要using
,为什么不只是typedef
?
template <typename T>
class Sub : public Base<T>
{
typedef Base<T> Base;
};
相关文章:
- .cpp和.h文件中的模板专用化声明
- 未在作用域中声明unordered_map
- C++避免重复声明的语法是什么
- 如何确保C++函数在定义之前声明(如override关键字)
- 错误:未在此范围内声明'reverse'
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 为什么在定义函数之前先声明它
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- #ifdef和未声明的标识符
- 没有显式声明的int[]中的foreach
- 在基于范围的for循环中使用结构化绑定声明
- 在将变量声明为引用时,堆在释放后使用
- C++:无法访问声明的受保护成员
- 在"template"和函数声明之间使用:template<typename trait> using tr = base_trait<trait> void fn(tr::t
- 第二个指定的类型在模板typename声明中意味着什么
- C++在继承构造函数中使用具有typename的声明
- "typename qualified-id"引用非类型参数声明中的类型
- 匿名模板typename/class声明
- 正向声明-Typename C++错误
- 函数模板:typename声明