VIDTAKER.COM

Q&A

部分は関数で注文コンテキストをundeduced有するテンプレート。


別の質問を読んでいる、私はこの問題に部分的な、その一次のテストケースに削減順序に付属

template<typename T>
struct Const { typedef void type; };

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

int main() {
  // GCC chokes on f(0, 0) (not being able to match against T1)
  void *p = 0;
  f(0, p);
}

両方の関数では、オーバーロードの解決に入る専門の関数の型をテンプレートですvoid(int, void*) 。しかし、部分的には(コモーとGCCに応じて)今では2番目のより専門的なはテンプレートという順序。しかし、なぜ?

私は、部分的で注文に行くとどこで質問があるお見せしましょう。 5月Q一意に開くタイプの部分に応じて順序を決定するために使用される14.5.5.2

  • 変換されたパラメータリストのT1 (Q)は挿入: (Q, typename Const<Q>::type*) 。引数の型がありますAT = (Q, void*)
  • 変換されたパラメータリストのT2 (Q)は挿入: BT = (T, typename Const<T>::type*) 、これも引数の型です。
  • 禁煙はパラメータリストを変換(T, void*)14.8.2.1
  • 禁煙はパラメータリストを変換14.8.2.4A

Cは+が03アンダー、これを指定すると、私は、私がに関するいくつかの不具合の報告を読む意図を使用していた。上記の変換パラメータリストP (と呼ばれる{私)によっては、引数リストとして使用される(Q, T) ""関数呼び出しのやるべきテンプレート引数から。

,変換する必要はありません(void*, void*)または}それ自体がもう(のように、参照宣言子等除去)、およびまっすぐ行くT 、その各々独立のために(void*, typename Const<T>::type*) / typename Const<T>::type*ペアは型推論を行う:

  • void*に対して4.44.1template<typename T> struct Const { typedef void type; }; template<typename T> void f(T, typename Const<T>::type*) { cout << "Const"; } // T1 template<typename T> void f(T, void*) { cout << "void*"; } // T2 template<> void f(int, void*) { } // main.cpp:11: error: ambiguous template specialization // 'f<>' for 'void f(int, void*)' ここだけのテンプレートパラメータ、およびそれを見つけることですがでなければなりません 。タイプ控除は自明の成功に対して

  • に対して 。これは、を見つけるようにもここに。 非推定コンテキストなので、それが何かを推測するために使用されません。


ここに私の最初の質問:ウィルこれは現在の値を使って最初のパラメータ推定?答えはノーし、テンプレートの最初より専門的なである場合。両方のGCCとコモーは、2番目のより専門的なはテンプレートと言うので、これは場合、することはできませんし、私は彼らが間違っているとは思わない。そこで、"はい"を、挿入と仮定 。項( )を明示的意見"の各ペア控除は、独立していることと、その結果がいる結合"ともある"でコンテキストしかし、控除型ではない値がない参加ではなく値をの使用またはテンプレート他の引数を推定したか指定された。"これはあまりにも"音のような"はい。

控除したがって、あまりにも、すべてのA / Pのペアが成功します。今、各テンプレートには、少なくともとして特化され、他の控除は、任意の暗黙の型変換に依存していないため、両方の方向に成功した。その結果、呼び出しがあいまいである。

2回目の質問:今、なぜ実装は、2番目のより専門的なはテンプレートと言うんですね?ポイントは何か私は見過ごす?


編集 :私 、明示的な専門とインスタンスをテストし、両方の(最近のGCCバージョン )は、専門への参照があいまいです、教えているGCCの古いバージョン( )は、あいまいさのエラーを上昇していません。これは、最近のGCCのバージョンが不整合な部分関数の順序を持って提案テンプレート。



3 Replies

1)

T1は(Qが挿入された変換されたパラメータリスト):(Qが型名のconst::タイプ*)。引数の型)がいるのAT =(問、void *を

それは本当に正しい簡素れている場合のだろうか。入力するときはを合成Qれ、あなたが専門性を呼び起こすを許可Constテンプレートのspecliazation順序を決定する目的のために?

template <>
struct Const<Q> { typedef int type; }

これは意味することT2少なくともとして特化されていませんT1からvoid*パラメータが一致しない 'は任意のテンプレートパラメータを指定された2番目のパラメータです。


2)

を編集:学んだ後、 1417のダググレで()の実装アルゴリズムのその部分の順序、私はポスターの残りの部分に同意をする必要が来て、元の例ではない'あいまい意図する'は-にもかかわらず、標準はクリアされていないとしてそれはこのような状況で起こるかについてかもしれない。私は)編集この記事を自分自身の利益&参考のために私の改正の考えを(を示す必要があります。特に1417のアルゴリズムでは明らかにそれがtypename Const<T>::type 'にvoid'を部分的にご注文ステップの間に翻訳されていません - と各A / Pのペアは、互いに独立して推定であること。

当初、私はなぜ次のあいまいな考えられていただろうか:

        template<class T> void f(T,T*);  // 1

        template<class T> void f(T, int*); // 2

        f(0, (int*)0); // ambiguous

(The above is ambiguous because one cannot deduce f1(U1,U1*) from f2(T,int*), and going the other way, one cannot deduce f2(U2,int*) from f1(T,T*). Neither is more specialized.)

しかし、次のあいまいではない:

        template<class T> struct X { typedef int type; };
        template<class T> void f(T, typename X<T>::type*); // 3
        template<class T> void f(T, int*); // 2

以下は、発生した場合(理由の1つは、それがあいまいなことを期待する可能性がある:
- f3(U1,X<U1>::type*) -> f3(U1, int*) ==> f2(T,int*) (deduction ok, T=U1)
- f2(U2,int*) ==> f3(T, X<T>::type*) (deduction ok, T=U2 makes X<U2>::type* -> int*)
これが本当ならば、どちらも1つは他よりも専門になります。)

ことが明らかに、彼らは治療さ1417の部分順序アルゴリズムを学んだ後、'3'、上記のことがあったかのように:

template<class T, class S> void f(T, S*); // 4

いくつかのユニーク'のように控除のU'に対して型名のX::type'は成功する -

  • f3(U1,X<U1>::type*) is treated as f3(U1, U2*) ==> f2(T,int*) (deduction not ok)
  • f2(U2,int*) ==> f3(T,S* [[X<T>::type*]]) (deduction ok, T=U2, S=int)

そして'2'は、明らかに'3'よりも専門です。


3)

ここではこの時点で行く私です。私は同意チャールズベイリー 、不正のステップは、から行くことですConst<Q>::Type*void*

template<typename T>
void f(T, typename Const<T>::type*) { cout << "Const"; } // T1

template<typename T>
void f(T, void*) { cout << "void*"; } // T2

手順は、我々が持っていくと思う:

14.5.5.2 / 2

2つのオーバーロードされた関数を考えると、1つのかどうか以上の別のそれぞれが順番にテンプレート引数控除(14.8.2)他のそれを比較に使用して変換によって決定することができる特殊なテンプレートです。

14.5.5.2/3-b1

各タイプについては、テンプレートパラメータをユニークなタイプの代替を合成、その関数のパラメータリスト内のパラメータ、または変換関数、戻り値の型のテンプレートの各発生します。

私の意見では、型として合成される次の:

(Q, Const<Q>::Type*)    // Q1
(Q, void*)              // Q2

私は必要なすべての文言が表示されない2番目の合成パラメータのT1されるT 。私は任意の先例の他のコンテキストのいずれかがわからない。タイプQ C + +の型システム内で完全に有効なタイプです。

だから今我々は控除の手順を実行:

T1に第2四半期

我々は、T1のように我々はテンプレートパラメータを推測しようとすると:

  • パラメータ1: Const<Q>::typeする推測されますtemplate<typename T> struct Const; template<typename T> void f(T, typename Const<T>::type*) // T1 { typedef typename T::TYPE1 TYPE; } template<typename T> void f(T, void*) // T2 { typedef typename T::TYPE2 TYPE ; } template<> struct Const <int> { typedef void type; }; template<> struct Const <long> { typedef long type; }; void bar () { void * p = 0; f (0, p); }
  • パラメータ2:Nondeducedコンテキスト

パラメータには、2つの非推定コンテキストであっても我々はTの値を持つので、控除はまだ成功している

第1四半期にT2の

T2の我々はテンプレートパラメータをやるべき:

  • パラメータ1: Const<int>::typeする推測されますConst<Q>::type*
  • パラメータ2: template <typename T, int I> class Const { public: typedef typename Const<T, I-1>::type type; }; template <typename T> class Const <T, 0> { public: typedef void typ一致しないので、控除に失敗しました。

私見では、ここでどこに基準が私たちをことができますです。それは実際に明確に何が起こる必要がありますないので、パラメータが依存していないですが、14.8.2.1 / 3を読んで細目に基づいて、私の経験は()であることもここでパラメータタイプPに依存し、引数の型が一致する必要がないそれは。

T1の合成引数はT2を専門にではなく、逆に使用することができます。 T2はそのためより専門的なものT1ですので、最高の機能です。


更新1:

ちょうどpoingについてカバーするためにボイドされて。次の例を考えてみましょう:

上記では、 私たちはいつものオーバーロードの解決規則を実行しているが、使用されていないときは、部分的なオーバーロードのルールになる。これは、任意の専門を選択する正しいことはない 。これは、直感的に、ではないかもしれないコンパイラは、非常にフォームのsynthasizedタイプを持って満足していると型推論中にそれを使用する。


更新2