C++11中using语法解析及用法

一、using的所有语法功能

using这个关键字当然不是在C++11中添加的,但的确是在C++11中扩展了这个关键字的意义,其中最关键的扩展就是增加alias这种语法意义。直接查看gcc的代码,可以清晰的看到using关键字的所有用法及意义。在gcc-4.9.0\gcc\cp\parser.c文件的cp_parser_block_declaration函数中,即使通过注释也可以看到这个关键字的主要功能分为三种:using-declaration, a using-directive, or an alias-declaration。三种语法的解析也比较直观:如果using后面直接跟着namespace关键字,则是一个directive;如果下一个是一个变量名并且第三个token是等号则认为是一种类型别名,否则落入第三种using声明。
static void
cp_parser_block_declaration (cp_parser *parser,
bool statement_p)
{
……
/* If the next keyword is `using', we have a
using-declaration, a using-directive, or an alias-declaration. */
else if (token1->keyword == RID_USING)
{
cp_token *token2;

if (statement_p)
cp_parser_commit_to_tentative_parse (parser);
/* If the token after `using' is `namespace', then we have a
using-directive. */
token2 = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token2->keyword == RID_NAMESPACE)
cp_parser_using_directive (parser);
/* If the second token after 'using' is '=', then we have an
alias-declaration. */
else if (cxx_dialect >= cxx11
&& token2->type == CPP_NAME
&& ((cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_EQ)
|| (cp_nth_tokens_can_be_attribute_p (parser, 3))))
cp_parser_alias_declaration (parser);
/* Otherwise, it's a using-declaration. */
else
cp_parser_using_declaration (parser,
/*access_declaration_p=*/false);
}
……
}

二、using declaration的解析及意义

同样在不纠结细节的情况下,这里解析的方法就是首先解析所有的作用域(使用"::"表示),直到剩余最后一个identifier,这个identifier将会作为使用整个作用域的一个handle,其实从另一个角度看一认为是一个alias,或者是文件系统中的“链接”:因为本质上是通过一个较短的identifier名称来指代一个更长更完整的变量名。
gcc-4.9.0\gcc\cp\parser.c
static bool
cp_parser_using_declaration (cp_parser* parser,
bool access_declaration_p)
{
……
qscope = cp_parser_nested_name_specifier (parser, typename_p,
/*check_dependency_p=*/true,
/*type_p=*/false,
/*is_declaration=*/true);
……
/* Parse the unqualified-id. */
identifier = cp_parser_unqualified_id (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*declarator_p=*/true,
/*optional_p=*/false);
……
do_local_using_decl (decl, qscope, identifier);
else
do_toplevel_using_decl (decl, qscope, identifier);
……
}
大家应该都知道在子类中使用using可以引入父类的函数从而绕开“名字隐藏”(name hiding),但是从这个语法解析上看,它还有一个避免歧义的作用,例如下面的例子,如果没有D中的using声明,在main函数中直接使用d.x会有语法错误
tsecer@harry: cat using.base.var.cpp
struct B
{
int x;
};
struct B1
{
int x;
};

struct D: public B, B1
{
using B::x;
};

int main()
{
D d;
return d.x;
}
tsecer@harry: gcc -std=c++11 using.base.var.cpp
tsecer@harry:

三、using作为别名机制

如果第三个字符是“=”那么此时作为别名机制来解析。从实现上看,这个更像是一个语法糖结构,也就是把通过using形式定义的类型变量转换为“类型+变量”的声明结构。
static tree
cp_parser_alias_declaration (cp_parser* parser)
{
……
id = cp_parser_identifier (parser);
……
type = cp_parser_type_id (parser);
……
declarator = make_id_declarator (NULL_TREE, id, sfk_none);
declarator->id_loc = id_location;

member_p = at_class_scope_p ();
if (member_p)
decl = grokfield (declarator, &decl_specs, NULL_TREE, false,
NULL_TREE, attributes);
else
decl = start_decl (declarator, &decl_specs, 0,
attributes, NULL_TREE, &pushed_scope);
……
}

posted on 2020-09-14 19:01  tsecer  阅读(2559)  评论(0编辑  收藏  举报

导航