[英]c++11 parameter pack wrong behaviour with Apple LLVM 7.0.0 but works with GCC-5.1
由於該問題的先前版本,感謝@Gene,我現在可以使用一個更簡單的示例重現此行為。
#include <iostream>
#include <vector>
class Wrapper
{
std::vector<int> const& bc;
public:
Wrapper(std::vector<int> const& bc) : bc(bc) { }
int GetSize() const { return bc.size(); }
};
class Adapter
{
Wrapper wrapper;
public:
Adapter(Wrapper&& w) : wrapper(w) { }
int GetSize() const { return wrapper.GetSize(); }
};
template <class T>
class Mixin : public Adapter
{
public:
//< Replace "Types ... args" with "Types& ... args" and it works even with Apple LLVM
template <class ... Types>
Mixin(Types ... args) : Adapter(T(args...)) { }
};
int main()
{
std::vector<int> data;
data.push_back(5);
data.push_back(42);
Mixin<std::vector<int>> mixin(data);
std::cout << "data: " << data.size() << "\n";
std::cout << "mixin: " << mixin.GetSize() << "\n";
return 0;
}
使用Apple LLVM的結果,並通過-std=c++11
和-std=c++14
:
data: 2
mixin: -597183193
有趣的是,我還在@ideone上測試了此代碼,該代碼使用了啟用了C ++ 14的gcc-5.1,並且可以按預期工作!
data: 2
mixin: 2
為什么mixin.GetSize()
在Clang上返回垃圾值,為什么它在GCC-5.1中起作用?
@Gene建議我使用Types ... args
來創建向量的臨時副本(使用Types& ... args
使其可以與LLVM一起使用),但是該副本將包含相同的元素(因此也具有相同的元素)尺寸)。
您有一個懸空的引用,並且mixin.GetSize()
產生未定義的行為 :
Mixin
的構造函數內部, T
= std::vector<int>
,因此Adapter(T(args...))
將Adapter
的構造函數傳遞給臨時的std::vector<int>
Adapter
的構造函數參數是Wrapper&&
,但我們將其傳遞給std::vector<int>&&
,因此我們調用Wrapper
的隱式轉換構造函數 Wrapper
的構造函數參數是std::vector<int> const&
,我們將其傳遞給std::vector<int>&&
; 允許將rvalue綁定到const-lvalue引用,因此在語法上可以很好地進行編譯,但是實際上,我們將Wrapper::bc
綁定到了一個臨時對象 Mixin
的構造函數中創建的臨時項的生存期結束,並且Wrapper::bc
成為懸空引用; 調用Adapter::GetSize
現在產生UB 當Mixin
的構造函數參數從Types...
更改為Types&...
, Adapter(T(args...))
仍將 Adapter
的構造函數傳遞給臨時std::vector<int>
; 它之所以似乎起作用,是因為您看到的是UB的不同表現形式(可能是由於減少了std::vector<int>
的副本,所以堆棧看起來有些不同)。 即, 兩個版本的代碼都同樣損壞/錯誤!
因此,要具體回答:
為什么
mixin.GetSize()
在Clang上返回垃圾值,為什么它在GCC-5.1中起作用?
因為未定義的行為是未定義的行為。 ;-]出現工作是一種可能的結果,但是代碼仍然被破壞,正確的表象純粹是膚淺的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.