Clang 不允许 static_cast 到带有模板的父类,而 g++ 和 icc 允许

Posted

技术标签:

【中文标题】Clang 不允许 static_cast 到带有模板的父类,而 g++ 和 icc 允许【英文标题】:Clang does not allow static_cast to parent class with template, while g++ and icc allow 【发布时间】:2013-06-22 22:34:36 【问题描述】:

我正在尝试我的 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 扩展支持?还是未定义的行为?

【问题讨论】:

我认为(但不确定)V 在其成员的声明符(包括尾随返回类型)中不完整,因此不允许对其基类进行 static_cast,因为它需要一个完整的类型。我更确定它不完整的事实然后关于这不允许演员表。 你可以试试*static_cast&lt;std::valarray&lt;T&gt;*&gt;(this) 或者直接使用decltype(begin(valarray&lt;T&gt;())) 这并不能回答您的问题,但clang 似乎更喜欢*static_cast&lt;std::valarray&lt;T&gt;*&gt;(nullptr) 的更常见使用模式 我不明白为什么它需要一个完整的类型。可以将不完整的类型传递给引用参数(复制或移动构造函数)。 【参考方案1】:

代码非常危险,即使是 GCC 和 ICC 也需要修复。

您正在对值类型执行static_cast,而不是引用或指针。这会创建一个新的临时 valarray 对象,因此会调用 beginconst 重载(可能不是您想要的),并且 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,它只需要知道在 valarray&lt;T&gt; 上调用 std::begin 的类型,因此类型是否不完整并不重要,因为你没有'不需要演员表。

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

【讨论】:

以上是关于Clang 不允许 static_cast 到带有模板的父类,而 g++ 和 icc 允许的主要内容,如果未能解决你的问题,请参考以下文章

不允许clang中变量名中的Unicode/特殊字符?

带有多个参数的 static_cast 是怎么回事?

为啥clang++更喜欢adcx而不是adc

gcc有薄lto吗?

带有“#”的 Clang 诊断标志会导致构建错误

如何使用 Clang 在 C 程序中嵌入 LLVM 程序集或内在函数?