same_asコンセプトが型の等価性を2回チェックするのはなぜですか?


19

same_asコンセプトの可能な実装をhttps://en.cppreference.com/w/cpp/concepts/same_asで見ると、何か奇妙なことが起こっていることに気づきました。

namespace detail {
    template< class T, class U >
    concept SameHelper = std::is_same_v<T, U>;
}

template< class T, class U >
concept same_as = detail::SameHelper<T, U> && detail::SameHelper<U, T>;

最初の質問は、なぜSameHelperコンセプトが必要なのかということです。二つ目は、なぜあるsame_asかどうかを確認するTと同じであるUU同じT?冗長ではないですか?


SameHelper<T, U>本当かもしれないからといって、そうであるとは限らないSameHelper<U, T>
一部のプログラマー、

1
それがポイントです、aがbと等しい場合、bはaと等しくありませんか?
user7769147

@ user7769147はい、これはその関係を定義しています。
フランソワアンドリュー

4
std :: is_sameのドキュメントには、「可換性は満たされています。つまり、TとUの2つのタイプのis_same<T, U>::value == true場合、TとUの場合に限り、is_same<U, T>::value == true」ということさえあります。これは、この二重チェックが必要ないことを意味します
Kevin

1
いいえ、これは間違っています。std:: is_sameは次のように述べています。条件が満たされている場合にのみ、2つの型に可換性があります。これは必ずしもそうではありません。しかし、2つの非可換型の例を見つけることができません。
Nemanja Boric

回答:


16

興味深い質問です。私は最近、コンセプトに関するAndrew Suttonの講演を見て、Q&Aセッションで誰かが次の質問をしました(次のリンクのタイムスタンプ): CppCon 2018:Andrew Sutton「60のコンセプト:知っておくべきことすべて、あなたが知らないこと」

したがって、質問は次のように要約されますIf I have a concept that says A && B && C, another says C && B && A, would those be equivalent?。Andrewは「はい」と回答しましたが、コンパイラにはいくつかの内部メソッド(ユーザーには透過的)があり、概念をアトミックな論理命題に分解して(atomic constraintsAndrewが用語を述べたように)、それらがそうであるかどうかを確認します同等。

次に、cppreferenceが何について述べているかを見てくださいstd::same_as

std::same_as<T, U>包含std::same_as<U, T>およびその逆。

それは基本的に「if-and-only-if」関係であり、それらは互いに意味します。(論理的同等性)

私の推測では、ここに原子制約がありstd::is_same_v<T, U>ます。コンパイラは、治療方法は、std::is_same_vそれらを考えさせるかもしれないstd::is_same_v<T, U>し、std::is_same_v<U, T>二つの異なる制約(それらが異なる実体である!)など。したがってstd::same_as、そのうちの1つだけを使用して実装する場合:

template< class T, class U >
concept same_as = detail::SameHelper<T, U>;

その後std::same_as<T, U>std::same_as<U, T>異なる原子制約に「爆発」し、同等ではなくなります。

さて、コンパイラはなぜ気にするのですか?

この例を考えてみましょう:

#include <type_traits>
#include <iostream>
#include <concepts>

template< class T, class U >
concept SameHelper = std::is_same_v<T, U>;

template< class T, class U >
concept my_same_as = SameHelper<T, U>;

// template< class T, class U >
// concept my_same_as = SameHelper<T, U> && SameHelper<U, T>;

template< class T, class U> requires my_same_as<U, T>
void foo(T a, U b) {
    std::cout << "Not integral" << std::endl;
}

template< class T, class U> requires (my_same_as<T, U> && std::integral<T>)
void foo(T a, U b) {
    std::cout << "Integral" << std::endl;
}

int main() {
    foo(1, 2);
    return 0;
}

理想的には、my_same_as<T, U> && std::integral<T>包含しmy_same_as<U, T>ます。したがって、コンパイラーは2番目のテンプレート特殊化を選択する必要がありますが、それ以外は選択しません。コンパイラーはエラーを発行しますerror: call of overloaded 'foo(int, int)' is ambiguous

この背後にある理由は、以来ということですmy_same_as<U, T>し、my_same_as<T, U>お互いを包摂しない、my_same_as<T, U> && std::integral<T>my_same_as<U, T>(包摂の関係の下で制約の半順序集合上)無類なります。

ただし、交換した場合

template< class T, class U >
concept my_same_as = SameHelper<T, U>;

template< class T, class U >
concept my_same_as = SameHelper<T, U> && SameHelper<U, T>;

コードがコンパイルされます。


same_as <T、U>とsame_as <U、T>も異なる原子制約である可能性がありますが、それらの結果は同じです。コンパイラーがsame_asの定義を、論理的な観点から同じ2つの異なるアトミック制約としてそれほど重視しているのはなぜですか?
user7769147

2
コンパイラがされて必要な検討する任意の制約包摂のための明確なように、2つの式を、それは考えることができ、引数を明白な方法でそれらに。したがって、双方向を必要とするだけでなく(制約を比較するときに名前が付けられる順序が問題にならないようにするため)、同じ式からSameHelper2つの用途is_same_v派生させる必要があります。
Davis Herring

@ user7769147更新された回答を参照してください。
Rin Kaenbyou

1
概念の平等に関して従来の知恵は間違っているようです。がとis_same<T, U>同一であるテンプレートとは異なりis_same<U, T>、2つのアトミック制約は、同じ式で形成されていない限り、同一とは見なされません。したがって、両方の必要性。
AndyG

どうare_same_asですか?template<typename T, typename U0, typename... Un> concept are_same_as = SameAs<T, U0> && (SameAs<T, Un> && ...);場合によっては失敗します。たとえば、are_same_as<T, U, int>同等ではare_same_as<T, int, U>ないare_same_as<U, T, int>
user7769147

2

std::is_same 以下の場合に限り、trueとして定義されます。

TとUが同じ型に同じcv-qualificationsで名前を付けている

私の知る限り、標準は「同じ型」の意味を定義していませんが、自然言語と論理では「同じ」は同値関係であり、交換可能です。

この仮定が与えられた場合、私が推測すると、is_same_v<T, U> && is_same_v<U, V>実際には冗長になります。ただしsame_­as、に関しては指定されていませんis_same_v。それは説明のためだけです。

両方の明示的なチェックにより、の実装は可換でなくてもsame-as-impl満たすsame_­asことができます。この方法で指定すると、実装方法を制限することなく、概念の動作が正確に説明されます。

このアプローチがで指定する代わりに選択された正確な理由はis_same_v、私にはわかりません。選択したアプローチの利点は、2つの定義が分離されていることです。一方は他方に依存しません。


2
私はあなたに同意しますが、この最後の議論は少しストレッチです。私には、「ねえ、2つの型が同じかどうかを通知するこの再利用可能なコンポーネントがあります。今、型が同じかどうかを知る必要があるこの他のコンポーネントがありますが、以前のコンポーネントを再利用する代わりに、私はこのケースに固有のアドホックソリューションを作成します。これで、同等の定義を必要とする男を、同等の定義を持つ男から「分離」しました。
カシオレナン

1
@CássioRenanもちろん。私が言ったように、私はなぜだかわかりません、それは私が思いつくことができた最良の推論です。著者はより良い理論的根拠を持っているかもしれません。
eerorika
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.