namespaceの賢い使い方

#namespaceの賢い使い方

みんな大好き（？）、いなむ先生です。
本記事は初心者 C++er Advent Calendar 2015 6日目の穴埋め記事です。

__注意書き__
本記事は一般的なコーディングを賢く行うためのTips的記事です。

## 名前空間

名前空間は名前の衝突を防ぐために必要なものです。
`namespace`キーワードにつづいてお好きな名前を書き続いて`{}`で囲みます。
この中で書かれた名前は、外から呼ぶときには先頭に名前空間の修飾をつけなければなりません。
これにはoperator`::`（スコープ解決演算子と呼ばれる）を用います。

以下のコードを見てください:

```cpp
namespace A
{
    void f(){std::cout << "A" << std::endl;};
    void hoge(){
        f(); // 名前空間の中では修飾しなくても呼び出せる
    }
}

namespace B
{
    void f(){std::cout << "B" << std::endl;};
    void hoge(){
        A::f(); // 別の名前空間から呼びたいなら修飾する
    }
}

int main()
{
    A::f(); // A
    B::f(); // B
    A::hoge(); // A
    B::hoge(); // A
}
```

汎用性の高い名前を用いても名前を区別することができます。
(check, get, etc...)

標準ライブラリは`std`名前空間に定義されいます。
呼び出す場合は適切なヘッダをインクルードし、
`std::`で修飾して上げる必要があります。

いちいち名前空間で修飾するのは面倒ですので

```cpp
using namespace std ;
```

と書いてしまったコードもよく見かけます。

しかし、せっかく名前空間に宣言してあるコードを自分の名前空間やグローバルにすべて持ち込んでしまうのはあまりにお粗末です。

##名前の衝突

その理由の一つは、標準の関数と同じ名前（厳密にはシグネチャのこと）の関数を書いてしまった場合に起こります。

例：max
せっかく`std::max`という名前だったのに`using namespace std;`のせいで`std::max`が単なる`max`とおなじになり、自分の書いた`max`と区別がつかなくなる、ということが起こりえます。

```cpp
#include <iostream>

using namespace std;

template < typename T >
T max(T const& a, T const& b)
{
    return a < b ? b : a ;
}

int main(){
    cout << max(1,2) << endl; // エラーだよ
    return 0;
}
```

この例では、`std::cout`, `std::endl;`を`cout`, `endl`と書きたいだけで`max`のことは考えていませんが`std`名前空間には`max`が存在します。

標準にある関数名なんか書かないよと思った人いるかもしれません。
標準ライブラリはとてもとても多くの名前がありますので把握は不可能ですし、C++のバージョンを上げることも考えると名前が増えます。
例えばC++14までは`std::gcd`はありませんでしたからusing namespace std;した上でgcdを書いていても大丈夫でしたが、C++17を使うとアウトになります。


##namespaceの短縮（エイリアス）

名前空間に別名をつけることができます。

```cpp
namespace ns = very_very_long_namespace;
```

のようにすれば、長い名前空間を短くできます。

```cpp
namespace hoge = a::b::c::hoge;
```

のように深い名前空間をユーザーが別名をつけて使うのが一般的です。

###Using 宣言

using namespaceしてしまうと、名前空間にある名前が全てスコープ内に持ち込まれます。
上記の名前の衝突などが起こりえます。

そこで、次のように使う名前だけをusing 宣言します。

```cpp
using std::cout ; // std::cout を cout と書ける
using std::endl ; // std::endl を endl と書ける
```

これで影響を最小限にすることができます。

例えば、ある関数内でstd::begin, std::endを使う場合:

```cpp
template < class Range >
void f(const Range & range){
  using std::begin; // for ADL
  using std::end; // for ADL

  auto first = begin(range);
  auto last  = end(range);
  
  // ...
}
```

のようにすることでusingによる名前の持ち込みを関数のスコープ内に留めることができます。

またこのusingの使い方はオーバーロードの可視化によってADLのcandidate functionになるという利点があります。

実はusing std::beginしなくても

```cpp
std::vector<int> v;
auto first = begin(v);
```

のようにstd::beginとしなくてもvectorにbeginを適用することができます。
これはおなじstd名前空間にvectorとbeginが存在するからです。

関数（引数）

のように呼び出した場合。
引数の型が宣言されている名前空間から関数を検索するのです（雑
これを **ADL(Argument Dependent Lookup)** といいます。

ところで
begin()は **int[10]** のような配列にも使えますが **int[10]** は組み込み型なので名前空間に宣言されているわけではありません。

よって以下はエラーです:

```cpp
int arr[10];
begin(arr); // error
```

しかし`using std::begin;`しておけば`begin(arr)`としても問題ありません、鉄壁です。

これだけだとstd::begin使っておけばいいと思うかもしれません。

しかし次の場合を考えてください:

```cpp

namespace my_space {
  // 独自配列
  struct MyArray{ /* ... */};
  // MyArray専用begin
  decltype(auto) begin(const MyArray& a) { return /* ... */; }
}

template < class Range >
void f(Range&& range){
  using std::begin;
  auto first = begin(range);
}


```

fの引数はテンプレートなのでvectorかもしれませんし組み込みの配列かもしれませんし、**ユーザー定義型の配列** かもしれません！
もしMyArrayが引数なら`std::begin`ではなく`my_space::begin`を呼ばなければなりません。

`using std::begin`した上で`begin(range)`を書けば、MyArrayの場合ADLで`my_space::begin`が、vectorの場合も同様に`std::begin`が配列の場合でも`std::begin`はusingされているのでちゃんと呼ばれます。
という理由でこれが鉄壁の方法です。


基本的にヘッダに書くコード（ライブラリ）は名前空間の中に記述することが必要でしょう。

その理由の一つはこのグローバルに関数があると意図しないオーバーロード解決の対象になってバグの原因なるからです。

namespaceを賢く使いましょう。


## inline namespace

inline指定された名前空間は名前空間の修飾を省略できます。
もちろん修飾つきで呼ぶこともできます。

inline namespaceは上級者向けの機能です。
使いみちは主に以下の2つです:

- ライブラリ等でのAPIのバージョン管理

- using namespaceによる名前空間省略の階層の段階的管理

### ライブラリ等でのAPIのバージョン管理

inline namespace を使うことによってデフォルトの関数を切り替えるという使い方です。

```cpp
#include <iostream>

namespace my_lib {
  namespace v1 {
    void f()
    {
      std::cout << "v1" << std::endl;
    }
  }

  inline namespace v2 {
    void f()
    {
      std::cout << "v2" << std::endl;
    }
  }
}

int main()
{
  my_lib::v1::f(); // 古いバージョンのAPIを呼び出す
  my_lib::v2::f(); // バージョンを明示的に指定してAPIを呼び出す
  my_lib::f();     // ライブラリデフォルトのAPIを呼び出す
}
```

### using namespaceによる名前空間省略の階層の段階的管理

おそらくUDLs(User Defined Literals)を書くときに一番使うのです。
なぜなら、UDLsは名前空間のusing namespaceを前提としているからなのです。

```cpp
namespace my_literals {
inline namespace integer_literals {
inline auto operator"" _kilo(unsigned long long x)
  { return int(x) * 1'000; }
}
inline namespace floating_point_literals {
inline auto operator"" _kilo(long double x)
  { return double(x) * 1'000; }
}
}

int main() {
    {
        using namespace my_literals::integer_literals; // int用だけ可視化される
        1_kilo; // 1000
    }

    {
        using namespace my_literals::floating_point_literals; // double用だけ可視化される
        1_kilo; // 1000.0
    }

    {
        using namespace my_literals; // 全部可視化される
        1_kilo; // 1000
        1.0_kilo; // 1000.0
    }
}
```

UDLsにしても普通の関数のAPI群にしてもinline namespaceに格納しておけば可視化の範囲をユーザーが選択できるというメリットがあります。

##跋文

ミス、間違いがありましたら[いなむ先生](https://twitter.com/mitama_rs)までツイートしていただくかかコメントをいただけると嬉しいです。
できるだけ迅速に修正致します