目前为止C++中的using关键字主要有三中使用场景,从C++ 11开始新增了第三种。下面我们分别介绍一下。
语法:
attr(optional) using namespace nested-name-specifier(optional) namespace-name;
attr: 应用到using的任意数量的属性,
nested-name-specifier: 名称和作用域解析运算符::的序列,以作用域解析运算符结尾。单个::引用全局命名空间。
namespace-name: 命名空间的名称。查找此名称时,只关注名称空间声明,也就是说只查找命名空间的名字。
using-directives只有在命名空间范围和块范围中才允许使用。从using-directives之后的任何名称的非限定名称查找的角度来看,直到它出现的作用域结束,namespace name中的每个名称都是可见的,就好像它是在最近的包含Using-directives和命名空间名称的封闭命名空间中声明的一样。
using-directives不会向它出现的声明区域添加任何名称(与using-declaration不同),因此不会阻止声明相同的名称。
using-directives对于非限定查找而言是可传递的:如果一个作用域包含一个指定名称空间名称的using-directives,而该指令本身又包含用于某个namespace-name-2的using-directives,其效果就像来自第二个命名空间的using-directives出现在第一个命名空间中。这些可传递名称空间发生的顺序不影响名称查找。
namespace A {
int i;
}
namespace B {
int i;
int j;
namespace C {
namespace D {
using namespace A; // all names from A injected into global namespace
int j;
int k;
int a = i; // i is B::i, because A::i is hidden by B::i
}
using namespace D; // names from D are injected into C
// names from A are injected into global namespace
int k = 89; // OK to declare name identical to one introduced by a using
int l = k; // ambiguous: C::k or D::k
int m = i; // ok: B::i hides A::i
int n = j; // ok: D::j hides B::j
}
}
namespace D {
int d1;
void f(char);
}
using namespace D; // introduces D::d1, D::f, D::d2, D::f,
// E::e, and E::f into global namespace!
int d1; // OK: no conflict with D::d1 when declaring
namespace E {
int e;
void f(int);
}
namespace D { // namespace extension
int d2;
using namespace E; // transitive using-directive
void f(int);
}
void f() {
d1++; // error: ambiguous ::d1 or D::d1?
::d1++; // OK
D::d1++; // OK
d2++; // OK, d2 is D::d2
e++; // OK: e is E::e due to transitive using
f(1); // error: ambiguous: D::f(int) or E::f(int)?
f('a'); // OK: the only f(char) is D::f(char)
}
注意: 不要在头文件的全局范围内使用using namespace。
将在别处定义的名称引入此using-declaration出现的声明区域中。这个需要注意定义冲突的问题。
void f();
namespace A {
void g();
}
namespace X {
using ::f; // global f is now visible as ::X::f
using A::g; // A::g is now visible as ::X::g
using A::g, A::g; // (C++17) OK: double declaration allowed at namespace scope
}
void h()
{
X::f(); // calls ::f
X::g(); // calls A::g
}
namespace A {
void f(int);
}
using A::f; // ::f is now a synonym for A::f(int)
namespace A { // namespace extension
void f(char); // does not change what ::f means
}
void foo() {
f('a'); // calls f(int), even though f(char) exists.
}
void bar() {
using A::f; // this f is a synonym for both A::f(int) and A::f(char)
f('a'); // calls f(char)
}
namespace A {
int x;
}
namespace B {
int i;
struct g { };
struct x { };
void f(int);
void f(double);
void g(char); // OK: function name g hides struct g
}
void func() {
int i;
using B::i; // error: i declared twice
void f(char);
using B::f; // OK: f(char), f(int), f(double) are overloads
f(3.5); // calls B::f(double)
using B::g;
g('a'); // calls B::g(char)
struct g g1; // declares g1 to have type struct B::g
using B::x;
using A::x; // OK: hides struct B::x
x = 99; // assigns to A::x
struct x x1; // declares x1 to have type struct B::x
}
namespace B {
void f(int);
void f(double);
}
namespace C {
void f(int);
void f(double);
void f(char);
}
void h() {
using B::f; // introduces B::f(int), B::f(double)
using C::f; // introduces C::f(int), C::f(double), and C::f(char)
f('h'); // calls C::f(char)
f(1); // error: B::f(int) or C::f(int)?
void f(int); // error: f(int) conflicts with C::f(int) and B::f(int)
}
namespace X {
namespace M {
void g(); // declares, but doesn't define X::M::g()
}
using M::g;
void g(); // Error: attempt to declare X::g which conflicts with X::M::g()
}
#include
#include
using std::string;
int main()
{
string str = "Example";
using std::cout;
cout << str;
}
#include
struct B {
virtual void f(int) { std::cout << "B::f\n"; }
void g(char) { std::cout << "B::g\n"; }
void h(int) { std::cout << "B::h\n"; }
protected:
int m; // B::m is protected
typedef int value_type;
};
struct D : B {
using B::m; // D::m is public
using B::value_type; // D::value_type is public
using B::f;
void f(int) { std::cout << "D::f\n"; } // D::f(int) overrides B::f(int)
using B::g;
void g(int) { std::cout << "D::g\n"; } // both g(int) and g(char) are visible
// as members of D
using B::h;
void h(int) { std::cout << "D::h\n"; } // D::h(int) hides B::h(int)
};
int main()
{
D d;
B& b = d;
// b.m = 2; // error, B::m is protected
d.m = 1; // protected B::m is accessible as public D::m
b.f(1); // calls derived f()
d.f(1); // calls derived f()
d.g(1); // calls derived g(int)
d.g('a'); // calls base g(char)
b.h(1); // calls base h()
d.h(1); // calls derived h()
}
Output:
D::f
D::f
D::g
B::g
B::h
D::h
1. using identifier attr(optional) = type-id ;
2. template < template-parameter-list >
using identifier attr(optional) = type-id ;
解释
1) 类型别名声明引入了一个名称,该名称可用作type-id表示的类型的同义词。它不引入新类型,也不能更改现有类型名称的含义。类型别名声明和typedef声明之间没有区别。此声明可能出现在块范围、类范围或命名空间范围中。
2) 别名模板是一个模板,在指定具体值时,它相当于将别名模板的模板参数替换为type-id中的模板参数的结果
Example
#include
#include
#include
// type alias, identical to
// typedef std::ios_base::fmtflags flags;
using flags = std::ios_base::fmtflags;
// the name 'flags' now denotes a type:
flags fl = std::ios_base::dec;
// type alias, identical to
// typedef void (*func)(int, int);
using func = void (*) (int, int);
// the name 'func' now denotes a pointer to function:
void example(int, int) {}
func f = example;
// alias template
template<class T>
using ptr = T*;
// the name 'ptr' is now an alias for pointer to T
ptr<int> x;
// type alias used to hide a template parameter
template<class CharT>
using mystring = std::basic_string<CharT, std::char_traits<CharT>>;
mystring<char> str;
// type alias can introduce a member typedef name
template<typename T>
struct Container { using value_type = T; };
// which can be used in generic programming
template<typename ContainerType>
void g(const ContainerType& c) { typename ContainerType::value_type n; }
// type alias used to simplify the syntax of std::enable_if
template<typename T>
using Invoke = typename T::type;
template<typename Condition>
using EnableIf = Invoke<std::enable_if<Condition::value>>;
template<typename T, typename = EnableIf<std::is_polymorphic<T>>>
int fpoly_only(T t) { return 1; }
struct S { virtual ~S() {} };
int main()
{
Container<int> c;
g(c); // Container::value_type will be int in this function
// fpoly_only(c); // error: enable_if prohibits this
S s;
fpoly_only(s); // okay: enable_if allows this
}