4

最近のすべての主要なコンパイラが使用した機能をサポートしているかどうかを確認するために C++11 コードを試しています。次の短縮コード

#include <valarray>

struct T
{
    double vv[3];
};

class V : public std::valarray<T>
{
    public:
        auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this)))
        {
            return std::begin(static_cast<std::valarray<T>>(*this));
        }
};

int main(void)
{

}

g++ 4.8.1 (Debian sid リポジトリから)、Intel C++ コンパイラ 13.1.1 20130313 でコンパイルされますが、Clang 3.3-2 (Debian sid リポジトリから) ではコンパイルされません。

指定されたエラーは次のとおりです。

test.cpp:11:73: error: no viable conversion from 'V' to 'std::valarray<T>'
    auto begin()->decltype(std::begin(static_cast<std::valarray<T>>(*this)))
                                                                    ^~~~~

ただし、このようなコード

namespace std
{
auto begin(V& vv) -> decltype(std::begin(static_cast<V::parent_t>(vv)))
{
    return std::begin(static_cast<V::parent_t>(vv));
}
}

3 つのコンパイラすべてでコンパイルされます。

私の質問は次のとおりです。コード自体は言語標準で許可されていますか、Clang が誤ってコンパイルしただけですか、それとも g++/icc 拡張機能でのみサポートされていますか? それとも未定義の動作ですか?

4

1 に答える 1

0

コードは非常に危険であり、GCC と ICC でも修正する必要があります。

static_cast参照やポインターではなく、値の型に対して実行しています。これにより新しい一時valarrayオブジェクトが作成されるため、 のconstオーバーロードbeginが呼び出され (おそらく意図したものではない)、返されたイテレータはbegin()すぐに範囲外になる一時オブジェクトを参照するため、返されたイテレータは無効であり、それを逆参照することは未定義の動作です。

コードは次のようにコンパイルされます。

    auto begin()->decltype(std::begin(std::declval<std::valarray<T>&>()))
    {
        return std::begin(static_cast<std::valarray<T>&>(*this));
        /* cast to reference type!    ^^^^^^^^^^^^^^^^^ */
    }

decltypeはキャストする必要はありません。の呼び出しのthisタイプを知る必要があるだけです。したがって、キャストは必要ないため、タイプが不完全であっても問題ありません。std::beginvalarray<T>

関数の本体では、とにかく型が完全であると見なされるため、キャストは有効です。

于 2013-09-21T12:01:53.213 に答える