10

Clang-3.2 はコンパイルでき、コードは期待どおりに動作します。

struct have_f { int f(int i) {return 10;} }; 

struct empty {};

template <class T> 
struct outer {
        T t; 

        // if T have f(), define  outer_f()
        template<class U=decltype(t.f(1))> 
        int outer_f(int i) { return t.f(i); }
};

int main() {
        outer<have_f>  o1;
        outer<empty>   o2;

        // to silence unused var warning
        return  o1.outer_f(10) + sizeof(o2); 
}

どのバージョンの GCC も次のように拒否します。

t.cc:13:6: error: ‘struct empty’ has no member named ‘f’
  int outer_f(int i) { return t.f(i); }
      ^

誰が正しいですか?GccまたはClang?

実際の回答なしで、同様の質問があったことに注意してください。

4

1 に答える 1

9

問題は14.6.3 [temp.nondep]だと思います:

1 - テンプレート定義で使用される非依存の名前は、通常の名前検索を使用して検出され、使用された時点でバインドされます。

与えられた例は、テンプレート定義内の不適切な式が " [テンプレート定義で] またはインスタンス化の時点で診断される可能性がある" ことを説明しています。

デフォルトのtemplate-argument (14.1p9)U=decltype(t.f(1))は、 のインスタンス化のコンテキスト内では依存しない名前struct outer(つまり、それ自体のテンプレートへのテンプレート引数に依存しない) であるため、struct outerwithのインスタンス化には不適切な形式です。 T = struct empty. 標準は、デフォルトのテンプレート引数が評価される場所を明示的に説明していませんが、唯一の賢明な結論は、それらが他の構成要素として扱われ、それらが発生した時点で (または、この例では、インスタンス化の時点で) 評価されるということです。struct outerテンプレート)。SFINAE が適用されるコンテキストに対して、コンパイラが非依存のデフォルトのテンプレート引数の評価を遅らせる余地はないと思います。

幸いなことに、解決策は簡単です。デフォルトのテンプレート引数Uを従属名にするだけです。

    // if T have f(), define  outer_f()
    template<class T2 = T, class U=decltype(static_cast<T2 &>(t).f(1))> 
    int outer_f(int i) { return t.f(i); }
于 2012-10-10T09:11:47.620 に答える