パラメーターの順序にとらわれないstd :: same_asの一般化された形式(つまり、2つ以上の型パラメーター)を実装する方法は?


8

バックグラウンド

概念std::same_asは順序にとらわれない(つまり、対称)ことを知っています。std::same_as<T, U>これは、std::same_as<U, T>関連する質問)と同等です。この質問では、より一般的なものを実装したいと思います。それはtemplate <typename ... Types> concept same_are = ...、パック内の型Typesが互いに等しいかどうかをチェックします。

私の試み

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

template <typename T, typename... Others>
concept same_with_others = (... && std::same_as<T, Others>);

template <typename... Types>
concept are_same = (... && same_with_others<Types, Types...>);

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

// Note the order <U, T> is intentional
template< class T, class U> requires (are_same<U, T> && std::integral<T>)
void foo(T a, U b) {
    std::cout << "Integral" << std::endl;
}

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

(ここでの私の意図は、パックで注文されたすべての可能なタイプのペアを列挙することです)

残念ながら、このコードはコンパイルできず、コンパイラーfoo(int, int)はへの呼び出しがあいまいであると不平を言っています。私はそれが同等are_same<U, T>are_same<T, U>はないと見なしていると信じています。コードがなぜ失敗するかを知りたいのですが、どうすれば修正できるのですか(コンパイラーがそれらを同等のものとして扱うため)?


私の腸はsame_with_others、型の可能なすべての順列で実行されるヘルパーが必要だと私に言っています。
StoryTeller-Unslander Monica

私があなたを正しく理解しているかどうかは完全にはわかりません。すべてのタイプ... Typesが同じかどうかを確認しますか?多分std :: conjunctionがあなたを助けるでしょう。ページの下部に、あなたのアプローチに似ている例があります。
チュリル

@ StoryTeller-UnslanderMonicaしかし、私はすでにパック内のタイプの可能なすべての順序付けられたペアを列挙しています。それで十分ではありませんか?または、コンパイラーは具体的な型なしではフォールドの等価性を判断できませんか?
Rin Kaenbyou

@churillこれをコンセプトに実装するつもりであり、パラメータの順序付けはコンセプトに特別な注意が必要です。
Rin Kaenbyou

分からないので、直感です。GCCの開発者である可能性もあります。また、まだ完全に実装されていない可能性もあります。
StoryTeller-Unslander Monica

回答:


5

問題は、このコンセプトで:

template <typename T, typename... Others>
concept are_same = (... && std::same_as<T, Others>);

この概念の正規化された形式は...それはまさにそれです。これを「展開」することはできません(何もすることはありません)。また、現在のルールは概念の「部分」を通じて正規化されません。

言い換えると、これが機能するために必要なのは、あなたのコンセプトが次のように正規化されることです:

... && (same-as-impl<T, U> && same-as-impl<U, T>)

に:

... && (is_same_v<T, U> && is_same_v<U, T>)

そして、その基礎となる制約が他の基礎となる制約を包含している場合、1つのフォールド式&&制約が別のフォールド式制約を包含することを検討してください&&。そのルールがあれば、それはあなたの例を機能させるでしょう。

将来的にこれを追加することは可能かもしれませんが、包摂ルールに関する懸念は、制約の包摂をチェックするためにコンパイラーがすべてを出て完全なSATソルバーを実装することを要求したくないことです。これはそれがそれをはるかに複雑にするようには思えません(私たちは本当に追加し&&||式をフォールド式を使用します)、ません。

ただし、このようなフォールド式の包摂are_same<T, U>があったとしても、包摂されないことに注意してくださいstd::same_as<T, U>。それは包み込むだけare_same<U, T>です。これが可能かどうかはわかりません。


2
ように私には驚くべきことである、これは動作しません。概念だけが包含できることは合理的です。しかし、私の意見で(... && C<T>)は、この概念 C<T>を包括しないと、多くのユーザーを驚かせるでしょう。
metalfox

@metalfox:正規化の私の読書から、あなたの例はうまくいくはずです(制約を使用すると、Demoを通じて明示的に機能します)。
Jarod42

@ Jarod42あなたが書いたものとmetalfoxが書いたものは同じものではありません-違いはmetalfoxが何を話しているかです。
バリー

@ Jarod42はい、それは機能します。これは、概念が制約の包含に関与し、フォールド式(概念を含む)を単一の概念に具体化したためです。残念ながら、あなたの答えで述べたように、フォールド式はそれらが作られる概念に正規化されていません。これも機能しません:godbolt.org/z/pjmKxR
metalfox

私が誤解しているかもしれないConstraint_normalizationを、その後: - /私は理解し((fold1<Ts> && ...) && (fold2<Ts> &&...))一緒(fold1<Ts> && ...)(fold2<Ts> && ...)、それは原子であるのに対し。
Jarod42

5

cppreference.com Constraint_normalizationから

他の式Eの正規形は、式がEで、パラメーターマッピングがIDマッピングであるアトミック制約です。これには、&&または||を折りたたむものも含め、すべての折りたたみ式が含まれます。演算子。

そう

template <typename... Types>
concept are_same = (... && same_with_others<Types, Types...>);

「アトミック」です。

したがって、実際are_same<U, T>are_same<T, U>は同等ではありません。

実装方法がわかりません:-(

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.