2009-03-14

ユーザー定義リテラルの不審な点

ユーザー定義リテラルは以下のように定義、使うことが出来る

KiloMeter operator "" _km ( const char*, std::size_t ) {/*実装*/}

auto TimeMachine = "141.622272"_km ; //OK
auto marathon = 42.195_km ; //OK 文字列にされて渡される。

さて、頭を悩ます不思議な定義がある。ドラフト規格の17.6.4.3 Reserved namesによれば、

17.6.4.3.3 Global names [global.names]
1 Certain sets of names and function signatures are always reserved to the implementation:
— Each name that contains a double underscore _ _ or begins with an underscore followed by an uppercase
letter (2.11) is reserved to the implementation for any use. — Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace.175

ダブルアンダースコア、もしくは、アンダースコアに続いて大文字で始まる名前は、いかなる目的においても、処理系用に予約されている。
アンダースコアで始まる名前は、グローバル名前空間において、予約されている。

では、上記の例は間違いではないかというと、そうではない。というのも、

17.6.4.3.6 User-defined literal suffixes [usrlit.suffix]
1 Literal suffix identifiers that do not start with an underscore are reserved for future standardization.

リテラル後置識別子のうち、アンダースコアで始まらないものは、将来の標準化のために予約されている。

アンダースコア以外を認めてしまうと、たとえば、0L、とか、0xff、などといった「ユーザー定義リテラル」が定義できてしまい、確かに問題だ。しかし、ユーザー定義リテラルのオーバーロードを定義する文法は、13.5.8 User-defined literalsに定義されているが、やはり普通の識別子である。ということは、17.6.4.3.3 Global namesで定義されている予約語の制限を受ける。しかし、同時に、17.6.4.3.6 User-defined literal suffixes で定義されているように、アンダースコアで始まらなければならない。これはいったいどうすればいいのだろう。

まず、ダブルアンダースコアで始まるものは論外である。アンダースコアに大文字で始まってもいけない。これはいいのだが、アンダースコアで始まるすべての名前は、グローバル名前空間で予約されている。では、何らかの名前空間の中でオーバーロードを定義しなければならないのだろうか。しかし、引数は組み込み型なので、ADLなど働くはずがない。名前の示すとおり、引数に依存した名前解決なのだから。ということは、ユーザー定義リテラルを使うのは、その定義された名前空間の中や、あるいはクラス内でなければならないのだろうか。つまり、グローバル名前空間では使えないのだろうか。

あるいは、予約されてるだけで、使うことは出来るんだ。だからGo ahead。気にするな。ということなんだろうか。それはないと思いたいが。

No comments: