# Strong Alias [base::StrongAlias](https://source.chromium.org/chromium/chromium/src/+/main:base/types/strong_alias.h;l=78;drc=b337f048544d14eeb1e8aa6ae1b54ec796936ba5)は型安全なtypedef。 例えば実体がどちらもint型の2つの型を`using`で定義した場合、以下のように互いの区別がつかない。 ```cpp= using Orange = int; using Apple = int; Apple apple(2); // Apple -> Orange への型変換をしちゃう Orange orange = apple; // Orange と Apple の operationをしちゃう Orange x = orange + apple; if (orange > apple); // コンパイルエラー:OrangeとAppleそれぞれでオーバーロードしたいのにできない void foo(Orange orange); void foo(Apple apple); ``` Strong Aliasはこれをいい感じにしてくれる。 ## 概要 StrongAliasは以下のように定義する。 ```cpp= using Orange = StrongAlias<class OrangeTag, int>; ``` ひとつめの型引数は`TagType`でこれは空のクラス。タグ用に使うだけ。 ふたつめの型引数は`UnderlyingType`で実体の値の型をあらわす。 中身の値は`orange.value()`または`*orange`といった感じで取り出すことができる。std::optionalと同じ。 StrongAliasを使うと上記の例がどうなるかと言うと ```cpp= using Orange = StrongAlias<class OrangeTag, int>; using Apple = StrongAliasM<class AppleTag, int>; Apple apple(2); // コンパイルエラー:中身は同じでも型が不一致 Orange orange = apple; // コンパイルエラー:違う型同士なので演算不可 Orange x = orange + apple; if (orange > apple); // 別々のオーバーロード関数としてコンパイル可 void foo(Orange orange); void foo(Apple apple); ``` これは例えば[IDの実装](https://source.chromium.org/chromium/chromium/src/+/main:content/browser/attribution_reporting/attribution_report.h;l=43;drc=c686e8f4fd379312469fe018f5c390e9c8f20d0d)に使われる。 ```cpp= using Id = base::StrongAlias<AttributionReport, int64_t>; ``` 中身はただのintだが、例えばIDがいくつかあってそれらを別々に扱いたい時に多分保全しやすい。 ## 実装 中身は比較的シンプル。 UnderlyingTypeである[`value_`](https://source.chromium.org/chromium/chromium/src/+/main:base/types/strong_alias.h;l=144;drc=b337f048544d14eeb1e8aa6ae1b54ec796936ba5)を持ち、ここに[constructor](https://source.chromium.org/chromium/chromium/src/+/main:base/types/strong_alias.h;l=83-85;drc=b337f048544d14eeb1e8aa6ae1b54ec796936ba5)で値をセットする。 これは`operator*()`や`value()`で取り出すことができるようになっている。 比較演算はUnderlyingTypeのdefaultを使用する。 ```cpp= friend auto operator<=>(const StrongAlias& lhs, const StrongAlias& rhs) = default; friend bool operator==(const StrongAlias& lhs, const StrongAlias& rhs) = default; ``` 比較演算を使いたいならUnderlyingTypeの`operator<`などを定義しておく必要がある。 ### Hasher unordered_mapやunordered_setの要素としてStrongAliasを使おうとすると問題が発生する。 ```cpp= using MyType = base::StrongAlias<...>; using MySet = std::unordered_set<MyType>; ``` 曰くstd::hashの特殊化はcoding規約的に駄目らしい。 hashを使うために[StrongAlias::Hasher](https://source.chromium.org/chromium/chromium/src/+/main:base/types/strong_alias.h;l=127;drc=b337f048544d14eeb1e8aa6ae1b54ec796936ba5)が定義されている。 ```cpp= struct Hasher { using argument_type = StrongAlias; using result_type = std::size_t; result_type operator()(const argument_type& id) const { return std::hash<UnderlyingType>()(id.value()); } }; ``` これは以下のように使う。 ```cpp= using MyType = base::StrongAlias<...>; using MySet = std::unordered_set<MyType, typename MyType::Hasher>; ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up