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<std::valarray<T>*>(this)
或者直接使用decltype(begin(valarray<T>()))
这并不能回答您的问题,但clang 似乎更喜欢*static_cast<std::valarray<T>*>(nullptr)
的更常见使用模式
我不明白为什么它需要一个完整的类型。可以将不完整的类型传递给引用参数(复制或移动构造函数)。
【参考方案1】:
代码非常危险,即使是 GCC 和 ICC 也需要修复。
您正在对值类型执行static_cast
,而不是引用或指针。这会创建一个新的临时 valarray
对象,因此会调用 begin
的 const
重载(可能不是您想要的),并且 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<T>
上调用 std::begin
的类型,因此类型是否不完整并不重要,因为你没有'不需要演员表。
在函数体中,类型被认为是完整的,所以强制转换是有效的。
【讨论】:
以上是关于Clang 不允许 static_cast 到带有模板的父类,而 g++ 和 icc 允许的主要内容,如果未能解决你的问题,请参考以下文章