一致するテンプレートクラスの部分クラステンプレートの特殊化が、テンプレートが一致しない別の部分的特殊化とあいまいであるのはなぜですか?


8

質問はタイトルの文章で説明するには難しすぎるかもしれませんが、これは最小限の例です:

#include <iostream>
#include <type_traits>

template <class T, class U, class Enabler>
struct my_trait : std::false_type
{};

template <class T, class U>
struct my_trait<T, U, 
                std::enable_if_t<std::is_same<T, U>::value>> : std::true_type
{};

template <class T>
class temped
{};

template <class T>
struct my_trait<temped<T>, temped<T>, void> : std::false_type
{};

template <class T, class U>
using trait_t = my_trait<T, U, void>;

int main()
{
    std::cout << std::boolalpha;
    std::cout << trait_t<int, float>::value << std::endl;   // false
    std::cout << trait_t<int, int>::value << std::endl;     // true

    // Compilation error: Ambiguous
    //std::cout << trait_t<temped<int>, temped<int>>::value << std::endl;
    return 0;    
}

godboltでも利用可能

基本的に、my_trait2つの部分的な特殊化を持つ2つの型(および特殊化のためのダミー型)を取る基本テンプレートクラスがあります。

  • 2つのタイプが同じ場合
  • 2つのタイプがtemped同じタイプのクラステンプレートのインスタンス化である場合

それがために推定されたタイプに複数の制限を入れ、「より専門」と感じるよう単純に、我々は、最初に曖昧にならない第2の部分特殊化を期待しているだろうTし、Uベーステンプレート上。それでも、主要なコンパイラーは、私たちが期待に反していたことに同意しているようです。


回答:


1

@superの削除された回答は、これを基本的に正しくしました。半順序でstd::enable_if_t<...>はありませんvoid。依存型としては、原則として完全に恣意的なものにすることができます。これは、部分的な順序付けの目的で、完全に一意のタイプと見なされます。

この不一致の結果として、部分的な順序付けの間の控除は両方向で失敗し、専門化があいまいです。


1
しかし、部分的な順序付けを行う場合、それは実際には依存型ではありませんか?それはですstd::enable_if_t<std::is_same<DummyT, DummyT>::value>ここでDummyT「合成」のみ、理論が、特定のタイプ(ある[temp.func.order] / 3)。
aschepler

「合成された一意の型」は、現在表示されている特殊化によって違いが生じない場合でも、その型を使用する追加の特殊化が存在する可能性があることも意味しますか?しかし、規格はそれをどこかに言っていますか?
aschepler

私はあなたのポイントを欠いているかもしれません:はstd_enable_if_t<>ステートメントtrait_t<int, int>::valueで優先される部分的な特殊化を提供するため、考慮されているように見えます void(そうでない場合、この式はベーステンプレートを選択することによりfalseと評価されるはずです)。一方、ステートメントtrait_t<temped<int>, temped<int>>::valueはあいまいさをもたらしますが、my_trait<temped<T>, temped<T>, void>私たちがより特殊化することを望んでいた部分的な特殊化は、void型を明示的に述べます。
Ad N

この1に関連している未解決の問題があります:wg21.link/CWG2160は(?)しかし、その場合には、控除は明らかに私はこの1つにその例を調整することはできませんよので、一方向に成功ありません。
ブライアン、

1
そしていずれにしても、OPの質問に対する「本当の」答えは、標準はこれについて明確ではないため、標準で明確になるまでこのようなコードを記述しないでください。
ブライアン

0

その理由は

std::enable_if_t<std::is_same_v<temped<int>, temped<int>> 

無効に解決すると、

my_trait<temped<int>, temped<int>, void>::value 

あいまいにtrueまたはfalseとして定義されています。enable_ifが解決するタイプを変更した場合、たとえばboolとすると、すべて正常にコンパイルされます


1
OPは、テンプレートの特殊化の部分的な順序付けのコンテキストで、あいまいである理由を尋ねています。に変更するstd::enable_if_t<*, bool>と、目的が無効になります(特殊化も有効になっていないため)。
Rin Kaenbyou
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.