2012-11-22 8 views
21

GCC 4.7.2とClang 3.1の両方でC++ 11コードをコンパイルしている間に、Clangがテンプレート引数を推論するのに問題が発生しました。 GCCは成功する。より抽象的な形で は、コードは次のようになります。テンプレートパラメータとしてのVariadicテンプレート:GCCではなく、Clangではなく

のsrc/test.cc:

struct Element { 
}; 

template <typename T> 
struct FirstContainer { 
}; 

template <typename T, typename U = Element> 
struct SecondContainer { 
}; 

template <template <typename> class Container> 
void processOrdinary(Container<Element> /*elements*/) { 
} 

template <template <typename, typename> class Container> 
void processOrdinary(Container<Element, Element> /*elements*/) { 
} 

template <template <typename, typename...> class Container> 
void processVariadic(Container<Element> /*elements*/) { 
} 

int main() { 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processOrdinary(SecondContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic(FirstContainer<Element>{}); 
    // This function instantiation works in both GCC and Clang. 
    processVariadic<SecondContainer>(SecondContainer<Element>{}); 
    // This function instantiation works in GCC but not in Clang. 
    processVariadic(SecondContainer<Element>{}); 
    return 0; 
} 

を標準の§14.8.2に§14.3.3の例と仕様を読んでから、私は控除がうまくいくはずだとは思いますが、私は確かに言えません。これは建物から得られる出力です:

mkdir -p build-gcc/ 
g++ -std=c++0x -W -Wall -Wextra -Weffc++ -pedantic -c -o build-gcc/test.o src/test.cc 
g++ -o build-gcc/test build-gcc/test.o 
mkdir -p build-clang/ 
clang++ -std=c++11 -Weverything -Wno-c++98-compat -c -o build-clang/test.o src/test.cc 
src/test.cc:34:3: error: no matching function for call to 'processVariadic' 
    processVariadic(SecondContainer<Element>{}); 
    ^~~~~~~~~~~~~~~ 
src/test.cc:21:6: note: candidate template ignored: failed template argument deduction 
void processVariadic(Container<Element> /*elements*/) { 
    ^
1 error generated. 
make: *** [build-clang/test.o] Fel 1 

なぜ結果は異なりますか?私のコードには不特定の動作やそのすべてが含まれていますか?クランは、この呼び出しの引数を推測しようとしている

+0

私はあなたに同意します。私がC++ 11最終草案で見たことは、これがうまくいくはずだということです。 14.3.3.3が特に適切です。 –

+0

あなたの例題に 'typedef int element;'がありません。 – Quuxplusone

+0

いいえ、コードの冒頭に、Elementという名前の構造体を定義します。 – psyill

答えて

7

processVariadic(SecondContainer<Element>{}); 

SecondContainerは、デフォルトのテンプレート引数を持っているので、これはと同等です:

processVariadic(SecondContainer<Element, Element>{}); 

したがって、それが持つテンプレート引数控除を行い、 P = Container<Element>およびA = SecondContainer<Element, Element>。それはすぐにContainerテンプレートパラメータがSecondContainerであることを推測することができます。

次に、テンプレート引数を考慮します。引数の型は完全に解決されているので、パラメータには多くの型が含まれている必要があります。または、控除が成功することはありません(デフォルトの引数を考慮しません)。だから、控除の失敗を警告します。


何が起こるはずですか?
[...]
[temp.deduct.type]p8の言葉、

テンプレート型引数T、テンプレートテンプレート引数TTまたはPAは、以下のいずれかの形式を持っている場合、私は推測することができるテンプレート非型引数で[...] <T>は少なくとも一つの引数をテンプレート引数リストを表しTT<T>
TT<i>
TT<>
句にはT<i>はテンプレート引数リストを表し、少なくとも1つの引数にはiが含まれ、<>には、テンプレート引数リストが含まれ、引数にはTまたはiが含まれません。

テンプレート引数を一致させるために、我々は[temp.deduct.type]p9に回す:

P<T><i>を含むフォームを持っている場合は、それぞれのテンプレート引数リストPの各引数Piがと比較されますAの対応するテンプレート引数リストの対応する引数Ai

ここでは2つのことがあります。 1つは、リストPiAiの長さが異なる場合(この場合のように)、このルールでは何も起こりません。共通の解釈では、一致しない項目が調べられないようです。もう1つは、Pの形式に<T>または<i>(テンプレートパラメータがないため、<>が含まれている)が含まれていないため、この規則に従わないことです。


したがって、Clangはこのコードを拒否しました。私はr169475に修正しました。

関連する問題