34

以下のコードは、Visual Studio 2013、gcc 4.8、clang 3.4、および clang 3.5 (Apple LLVM 6.0) でコンパイルされますが、clang 3.6 (Apple LLVM 6.1 経由) ではコンパイルされません。

このコードは、コードベースの複雑なクラスの簡略化されたバージョンであり、問​​題を示すために最低限必要なものです。

問題の核心は、 ;を受け入れるコンストラクターが存在するためTYPED_VALUE、3.6 では、のコピー構築がテンプレート化された型の変換演算子を評価することです。これによりが評価され、 の定義が必要になります(ここでは提供できません - 完全なコードでは循環依存が発生します)。STRINGSTRINGstd::is_constructibleSTRING

class STRING;

class TYPED_VALUE
{
public:
    TYPED_VALUE( const TYPED_VALUE& ) = default; // explicit or implicit doesn't make a difference
    TYPED_VALUE( const STRING & ) {}

    template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
    operator TYPE( void ) const = delete;
};

class TYPED_STORAGE
{
public:
    TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}

    TYPED_VALUE value;
};

エラーメッセージは

/type_traits:2329:38: error: incomplete type 'SICORE::STRING' used in type trait expression
    : public integral_constant<bool, __is_constructible(_Tp, _Args...)>
                                     ^
/main.cpp:348:99: note: in instantiation of template class 'std::__1::is_constructible<SICORE::STRING, const SICORE::STRING &>' requested here
        template< typename TYPE, typename std::enable_if<!std::is_pointer< TYPE >::value && !std::is_constructible< TYPE, const STRING& >::value && !std::is_constructible< TYPE, bool >::value, int >::type = 0 >
                                                                                                  ^
/main.cpp:349:9: note: while substituting prior template arguments into non-type template parameter [with TYPE = SICORE::STRING]
        operator TYPE( void ) const = delete;
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~
/main.cpp:355:56: note: while substituting deduced template arguments into function template 'operator type-parameter-0-0' [with TYPE = SICORE::STRING, $1 = (no value)]
        TYPED_STORAGE( const TYPED_VALUE &v ) : value( v ) {}
                                                       ^
/main.cpp:340:11: note: forward declaration of 'SICORE::STRING'
    class STRING;
          ^

私には、これは 3.6 のバグのように思えます。以前のバージョンでは、オーバーロードの解決により、テンプレート引数を評価することなく、コピー コンストラクターが最適であると判断されました。私にもっと;)

(これは、コンストラクターまたは変換演算子のいずれかを明示的にすることで修正できますが、それは私たちが望む動作ではありません)

答えを知っている標準的な専門家はいますか?

4

3 に答える 3

1

このエラーを生成するには Clang が正しいと思います。

段落 10 の C++ 標準の [temp.inst] セクションには、次のように記載されています。

関数テンプレートまたはメンバー関数テンプレートの特殊化がオーバーロードの解決を伴う方法で使用される場合、特殊化の宣言は暗黙的にインスタンス化されます (14.8.3)。

TYPE_VALUE のコンストラクターへの呼び出しのオーバーロード候補をランク付けするために必要な暗黙的な変換シーケンスを形成するには、変換演算子のインスタンス化が必要です。また、トレイトへの不完全な型パラメーターの使用は無効な型を形成しないため、これは置換の失敗ではなく、ハード エラーです。

于 2016-08-02T07:01:57.027 に答える
-1

テンプレートは必要に応じてインスタンス化されます。Clang 3.6 は、3.5 よりも前にテンプレートをインスタンス化する必要がある場所に DR を実装したと思います。

于 2015-08-13T17:31:30.890 に答える