免責事項
これは答えではなく、長いコメントです
私の言語弁護士のスキルは標準を完全に理解するには低すぎますが、ここでは、コードを実験して発見したいくつかのことを示します。以下のすべては、私が(完全とはほど遠い)問題についての理解に基づいており、おそらくいくつかのレビューが必要です。
調査
まず、完全に定義された標準バージョン(C ++ 17)に行ったので、明確に定義された実装で動作します。
このコードを見ると、テンプレートのインスタンス化と再定義に関しては、MSVCにはまだいくつかの問題があるようです(そのルックアップに関してはそうでしょうか?)。このシナリオでは、MSVCをそれほど信頼しません。
ということで、なぜtemplateキーワードが必要なのかを考えてみましょう
return yF.template head<1>();
従属名
時々、テンプレート内で、名前が参照するかどうかをコンパイラが決定するのを助ける必要があります
- 値
int T::x = 0、
- タイプ
struct T::x {};、または
- テンプレート
template <typename U> T::foo<U>();
値を参照する場合、何も行いません。タイプを参照する場合は、を使用する必要がありますtypename。また、テンプレートを参照する場合は、を使用しますtemplate。そのテーマの詳細については、こちらをご覧ください。
従属名の実際の定義に関しては、標準仕様を理解していませんが、ここにいくつかの観察があります。
観察
参照コードを見てみましょう
template <int N>
struct Matrix
{
template <int Idx>
int head() { return Idx; }
};
template <typename T>
struct Test
{
static constexpr int RayDim = 3;
int func() const
{
Matrix<RayDim> yF;
return yF.head<1>(); // clang complains, gcc and msvc are ok
}
};
struct Empty {};
int test()
{
Test<Empty> t;
return t.func();
}
通常RayDimは従属名である必要があります(テンプレート内にあるためTest)。これMatrix<RayDim>も従属名になります。とりあえず、それがMatrix<RayDim>実際に依存名であると仮定しましょう。これによりMatrix<RayDim>::head、依存する名前も作成されます。以来Matrix<RayDim>::headテンプレート機能があり、それ自体がテンプレートと使用するために私たちを必要とする適用上から依存名の規則、あるtemplateキーワードが。これはclangが不満を言っていることです。
ただし、RayDimは内Testでfunc定義され、同じテンプレート内でも定義されており、テンプレート化された関数自体ではないため、RayDim実際にはのコンテキストでの依存名ではないと思いますfunc。さらに、RayDimのテンプレート引数に依存しませんTest。この場合、Matrix<RayDim>およびMatrix<RayDim>::headそれぞれ、私たちは省略することを可能にする、非依存の名前になるtemplateキーワードを。これが、gcc(およびmsvc)がコンパイルされる理由です。
ここでもテンプレートを作成RayDimするとします
template <typename>
static constexpr int RayDim = 3;
gccもそれを依存名として扱います(これは正しいです。後でテンプレートの特殊化が行われる可能性があるため、その時点ではわかりません)。一方、msvcは、投げたすべてのものを喜んで受け入れます。
結論
RayDim依存関係の名前がであるかどうかで沸騰しているようTest<T>::funcです。Clangはそうだと考えていますが、gccはそうではありません。いくつかのより多くのテストから、これはclangがこの1つにあるmsvcサイドのように見えます。しかし、それはまた、それが独自のことをしているので、誰が知っていますか?
がインスタンス化RayDimされる時点で依存する可能性のある方法がないので、ここではgccを使用しfuncます。