目前为止C++中的using关键字主要有三中使用场景,从C++ 11开始新增了第三种。下面我们分别介绍一下。

指示使用某命名空间,对命名空间成员进行声明也就是说指明用哪个命名空间的成员

Using-directives:指示使用某命名空间,这也是最常见的使用方法

语法:

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: 使用using声明命名空间中的名称

将在别处定义的名称引入此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()
}

Using-declaration:声明类中的名称

#include <iostream>
#include <string>
using std::string;
int main()
{
    string str = "Example";
    using std::cout;
    cout << str;
}
#include <iostream>
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

type alias and alias template declaration:类型别名和别名模板声明,C++11新增

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 <string>
#include <ios>
#include <type_traits>
 
// 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<T>' 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
}
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐