2016-08-21 13 views
15

- 標準(例えばN4594。)operator""sのための2つの定義があります。もちろんstd :: litals :: ..のインラインネームスペースの利点は何ですか? C++で

namespace std { 
... 
inline namespace literals { 
inline namespace chrono_literals { 
// 20.15.5.8, suffixes for duration literals 
constexpr chrono::seconds operator"" (unsiged long long); 

string

namespace std { 
.... 
inline namespace literals { 
inline namespace string_literals { 
// 21.3.5, suffix for basic_string literals: 
string operator "" s(const char* str, size_t len); 

が、私はこれらの名前空間から得られるのだろうか(およびすべての内の他の名前空間)、もしそれらがinlineであれば。

私は彼らが別の名前空間の中にいると思ったので、互いに矛盾しませんでした。しかし、彼らがinlineであるとき、この動機は取り消されます、そうですか? 編集:Bjarne explainsの主な動機は「ライブラリのバージョン管理」ですが、これはここには当てはまりません。

"Seconds"と "String"のオーバーロードが区別され、そのために競合していないことがわかります。しかし、過負荷が同じであれば、それらは衝突するだろうか?または(inline?)namespace何とかそれを防ぐのですか?

したがって、inline namespaceに入っているものは何ですか? @Columboは以下の点を指摘しているように、解決されたインラインネームスペース全体でオーバーロードしていますが、それらは衝突しますか?彼らは機能の他のペアのようオーバーロードしているため

+1

あなたの質問は、インラインネームスペース間のオーバーロードに関するものです。その時は大丈夫じゃない。 – Columbo

+2

@Columbo確かに。また、 "インラインネームスペースは何ですか?"のためのdupではありません。なぜならその答えは* versioning * grmに関するものだからです。 – towi

+0

Re: 'unsiged long long'、おそらくそれは' unsigned ... 'のタイプミスです。 – agc

答えて

30

ユーザ定義リテラルsは、それらの異なる引数リストの上に、彼らはスコープの両方にある場合でも、secondsstring間の「衝突」しません:

string operator "" s(const char* str, size_t len); 
seconds operator "" s(unsigned long long sec); 
互いに競合しない、まだ using namespace std

void test1() 
{ 
    using namespace std; 
    auto str = "text"s; 
    auto sec = 1s; 
} 

は、両方のサフィックスがスコープ内にあり、かつ:

これは、このテストを実行することによって証明されます。

なぜinline namespaceが踊っていますか?

プログラマが望むように標準定義された名前を少ししか公開しないことを可能にすることが理論的根拠です。上のテストでは、stdライブラリ全体をtestに "インポート"しました。少なくとも#includeされているものと同じくらいです。

test1()namespace literalsinlineではありませんでした。ここで

は全体のstdをインポートせずに、リテラルを使用するには、より制限的な方法です:

void test2() 
{ 
    using namespace std::literals; 
    auto str = "text"s; 
    auto sec = 1s; 
    string str2; // error, string not declared. 
} 

これは、すべてのSTD-定義されたリテラルをもたらしますが、ではない(例えば)std::string

test2()namespace string_literalsinlineではなく、namespace chrono_literalsinlineではない場合、機能しません。

あなたはまた、単に文字列リテラルを公開に選択し、することができないクロノリテラル:

void test3() 
{ 
    using namespace std::string_literals; 
    auto str = "text"s; 
    auto sec = 1s; // error 
} 

それともクロノリテラルではなく文字列リテラル:最後にそこ

void test4() 
{ 
    using namespace std::chrono_literals; 
    auto str = "text"s; // error 
    auto sec = 1s; 
} 

クロノの名前のすべてを公開する方法です chrono_literals:

void test5() 
{ 
    using namespace std::chrono; 
    auto str = "text"s; // error 
    auto sec = 1s; 
} 

test5()は魔法のこのビットを必要とします。要するに

namespace chrono { // hoist the literals into namespace std::chrono 
    using namespace literals::chrono_literals; 
} 

inline namespace sが開発者にこれらのオプションのすべてが利用できるようにするツールです。

更新

OPは以下のいくつかの良いフォロー質問をします。このアップデートでは(うまくいけば)対応しています。

using namespace stdはいいですか?

によって異なります。 A using namespaceは、汎用目的のライブラリの一部であることを意図したヘッダーのグローバルスコープでは決して良い考えではありません。ユーザーのグローバル名前空間に多数の識別子を強制したくない。その名前空間はあなたのユーザーに属します。

グローバルスコープusing namespaceは、作成しているアプリケーションにのみヘッダーが存在し、そのヘッダーを含むすべてのもので使用可能なすべての識別子がある場合は、大文字でも構いません。しかし、あなたがグローバルスコープにダンプする識別子が多いほど、何かと衝突する可能性が高くなります。 using namespace std;は識別子のバンチを持ち込み、標準の新しいリリースごとにさらに多くをもたらします。だから私はusing namespace std;あなた自身のアプリケーションのためにヘッダーのグローバルスコープでお勧めしません。

しかし、私はusing namespace std::literalsまたはusing namespace std::chrono_literalsをヘッダー内のグローバルスコープで見ることができますが、アプリケーションヘッダーのみであり、ライブラリーヘッダーではありません。

私はusingディレクティブを関数スコープで使用したいのですが、識別子のインポートは関数のスコープに制限されています。このような制限で、競合が発生した場合は、修正する方がずっと簡単です。そして、最初は起こりにくいです。

std定義のリテラルは、となります。は、おそらく互いに矛盾しません(今日はありません)。しかし、あなたは

STD-定義されたリテラルは、ユーザー定義リテラルと決して競合がSTD-定義されたリテラルは_で始めることは決してありませんしますので...わかりませんし、ユーザ定義リテラル_で開始するを持っています。

また、ライブラリ開発者にとっては、大きなライブラリの複数のインラインネームスペース内に競合するオーバーロードがないことが必要ですか?

これは本当に良い質問ですが、私は陪審員がまだこれに出ていないと考えています。しかし、ちょうどが意図的にに異なるインラインネームスペースのユーザー定義リテラルを持つライブラリを開発しています。

https://github.com/HowardHinnant/date

#include "date.h" 
#include "julian.h" 
#include <iostream> 

int 
main() 
{ 
    using namespace date::literals; 
    using namespace julian::literals; 
    auto ymd = 2017_y/jan/10; 
    auto jymd = julian::year_month_day{ymd}; 
    std::cout << ymd << '\n'; 
    std::cout << jymd << '\n'; 
} 

上記のコードは、このエラーメッセージでコンパイルに失敗:

test.cpp:10:20: error: call to 'operator""_y' is ambiguous 
    auto ymd = 2017_y/jan/10; 
       ^
../date/date.h:1637:1: note: candidate function 
operator "" _y(unsigned long long y) NOEXCEPT 
^ 
../date/julian.h:1344:1: note: candidate function 
operator "" _y(unsigned long long y) NOEXCEPT 
^ 

_yリテラルがこのライブラリでyearを作成するために使用されます。そしてこのライブラリには、グレゴリオ暦(date.h)とユリウス暦(julian.h)があります。これらのカレンダーのそれぞれはyearクラス(date::yearjulian::year)です。グレゴリオ暦年はユリウス暦年と同じではないため、これらは異なる種類です。しかし、それらの名前をyearとし、両方に_yのリテラルを付けることは、まだ便利です。

Iは、次いで上記のコードからusing namespace julian::literals;を削除する場合は、コンパイルし、出力:

2017-01-10 
2016-12-28 

2016年12月28日ジュリアンは2017年1月10日グレゴリオと同じ日であることを実証しています。そして、これはまた、同じ日が異なるカレンダーで異なる年を持つことができるグラフィックデモです。

私は矛盾する使用が問題になるかどうかは時間だけでわかります。これまでのところそれはなかった。しかし、グレゴリオ暦以外のカレンダーでこのライブラリを使用した人はあまりいません。

+0

だから、私はこのことから、 'namespace std;を使うのは良い考えではありません。 'namespace std :: chrono_literals;のようなより具体的な名前空間を使用していますか?それとも根本的な結論ですか?この場合の過負荷は矛盾しないが、将来はどうなるのだろうか?また、ライブラリ開発者にとっては、大きなライブラリのいくつかのインラインネームスペース内に矛盾したオーバーロードを持たないことが必要ですか?この言語機能のための個人的なガイドラインを導き出すことは難しいです... – towi

+1

@towi:更新された答え。 –

+0

'using namespace std'を本格的に更新してくれてありがとうございました。私はもっと具体的にすべきでした。もちろん、私は関数や実装ファイルの中を意味していました。しかし、とにかくありがとう(他の読者が好きになる!)。そしてあなたのHinnant-Date-Exampleは優れていて、それらのオーバーロードがコンパイルされるのではなく、標準の設計によってコンパイルされた事故ではないことを示しています。良い。そしてあなたの日付ライブラリの例の最後の発言:これまでに見たタイプの安全性の中で最も狂った実装です: – towi

関連する問題