2017-02-23 12 views
43

クラステンプレートの特殊化を優先させるルールは、特殊化を関数テンプレートに書き直し、関数テンプレートの順序付けルール[temp.class.order] 。そして、この例を考えてみましょう:クラステンプレートの特殊な部分順序付けと関数の合成

#include <iostream> 

template <class T> struct voider { using type = void; }; 
template <class T> using void_t = typename voider<T>::type; 

template <class T, class U> struct A { }; 

template <class T> int foo(A<T, void_t<T>>) { return 1; } 
template <class T> int foo(A<T*, void>)  { return 2; } 

int main() { 
    std::cout << foo(A<int*, void>{}); 
} 

ここでどちらもgccと打ち鳴らす印刷2。前の例では意味がありますが、推測されていないコンテキスト(voidvoid_t<T>)に対する推測は無視されます。したがって、<T, void_t<T>><X*, void>に対して控除しますが、<T*, void><Y, void_t<Y>>に対して控除すると両方の引数で失敗します。ファイン。 12の間、あいまいなよう

#include <iostream> 

template <class T> struct voider { using type = void; }; 
template <class T> using void_t = typename voider<T>::type; 

template <int I> struct int_ { static constexpr int value = I; }; 

template <class T, class U> struct A  : int_<0> { }; 
template <class T> struct A<T, void_t<T>> : int_<1> { }; 
template <class T> struct A<T*, void>  : int_<2> { }; 

int main() { 
    std::cout << A<int*, void>::value << '\n'; 
} 

打ち鳴らすとgccレポートの両方この専門分野:

は今、この一般化を検討してください。しかし、なぜ?合成された関数テンプレートはあいまいではありません。これらの2つのケースの違いは何ですか?

+1

ページング@bogdan。 – Barry

+0

私は専門家ではありませんが、私はそれが 'void'と' void_t'の両方に特化していると思います。これは[作品](http://ideone.com/91pVA5) – xinaiz

+0

@BlackMosesそれは、部分的な注文はしません。一致する特殊化が1つだけある場合は、それがちょうど選択されました – Barry

答えて

4

ClangはGCC互換の(これらの両方の動作に依存する既存のコードと互換性があります)です。

[temp.deduct.type] P1を考えてみましょう:

[...]試みが(typeパラメータの型、非の値をテンプレート引数の値を見つけるために行われています型パラメータ、またはテンプレートパラメータ用のテンプレート)を使用します。

問題の重要な点は、ここを意味する。

部分的に関数テンプレートを注文するとき、Clangは単に両方向に推論します。一方の方向では控除が成功し、他方の方向では控除が成功すると、結果は「互換性がある」ことを意味し、それを順序付け結果として使用します。

しかし、クラステンプレートの部分的な特殊化を部分的に注文すると、 "互換性"は "同じ"を意味すると解釈されます。したがって、一方の部分専門化を他の部分専門化よりも専門化したとみなすのは、それらのうちの一方からの推論引数を元の部分専門化を再現する場合のみである。

これらの2つのいずれかを変更して、他の2つを一致させると、実質的な量の実質的なコードが壊れます。 :(

関連する問題