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));
}
}

将由所有三个编译器编译。

我的问题是:代码本身是语言标准允许的,只是 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!    ^^^^^^^^^^^^^^^^^ */
    }

Thedecltype不需要强制转换this,它只需要知道调用std::begina的类型valarray<T>,因此类型是否不完整并不重要,因为您不需要强制转换。

在函数体中,类型被认为是完整的,所以强制转换是有效的。

于 2013-09-21T12:01:53.213 回答