10

最新のclangバージョン3.4トランク187493)がコンパイルに失敗する非常に単純な(C++11)コードがありますが、GCCは正常にコンパイルされます。

コード (以下) は、function-templatefoofunction-local 型 Barでインスタンス化し、そのアドレスを class-template の非型テンプレート パラメーターとして使用しようとしますFunc

template<void(*FUNC_PTR)(void)>
struct Func {};

template<typename T> extern inline
void foo() {
    using Foo = Func<foo<T>>;
}
int main() {
    struct Bar {}; // function-local type
    foo<Bar>();
    return 0;
}

clang は次のエラーを出力します。

エラー: 非型のテンプレート引数がリンケージを持たない関数 'foo' を参照しています

ただし、型Barをグローバル スコープに移動すると (関数から取り出すことによって)、clang はそれを正常にコンパイルし、型がfunction-localであることが問題であることを証明します。

それで、clang はこのエラーを出力するのが正しいですか、それとも標準はこれをサポートしていませんか (その場合、GCC はそれを許可することで寛大すぎます)?


編集 #1:明確にするために、「ローカル型をテンプレート パラメーターとして使用できない」という制限が C++11 で削除されたため、これはこの質問の複製ではありません。ただし、ローカル型の使用に関連するリンケージの影響があるかどうか、およびこのエラーの発生において clang が正しいかどうかはまだ不明です。


編集 #2 :上記のコードのエラーを出力するのは clang が正しかった (@jxh からの回答を参照) が、次のコードのエラーも誤って出力すると判断されました (スコープからスコープにusing移動された宣言を使用):foo<Bar>()main()

template<void(*FUNC_PTR)(void)>
struct Func {};

template<typename T> extern inline
void foo() {}

int main() {
    struct Bar {};
    using F = Func<foo<Bar>>;
    return 0;
}
4

2 に答える 2

3

私はパーティーに遅れましたが、標準では、型ローカル関数にはリンケージがないと言われています (§3.5:8):

これらの規則でカバーされていない名前には関連性がありません。さらに、注記がある場合を除き、ブロック スコープ (3.3.3) で宣言された名前にはリンケージがありません

同じセクションは次のように続けます。

リンケージのない型は、外部リンケージを持つ変数または関数の型として使用してはなりません。

  • エンティティに C 言語リンケージ (7.5) がある、または
  • エンティティが名前のない名前空間 (7.3.1) 内で宣言されている、または
  • エンティティが ODR で使用されていない (3.2) か、同じ翻訳単位で定義されている。

実際のところ、Clang はこれを許可します。

namespace
{
    template<void (*FUNC_PTR)(void)>
    struct Func {};

    template<typename T>
    void foo() {}
}

int main() {
    struct Bar {}; // function-local type
    Func<foo<Bar>> x;
}

匿名の名前空間なしで拒否します。


EDIT 1 : jxh が指摘しているように、名前も同じ翻訳単位で定義されているため、これについてどう考えればよいかわかりません。


EDIT 2clangの人たちは、それがバグであることを確認しています。

于 2013-08-29T00:32:33.323 に答える