2017-09-28 108 views
14

即使使用了變量,我仍然面臨的一個問題是編譯器會抱怨一個未使用的變量,但它只用於參數包擴展中,對於特定的實例而言,它只是空的。 例如:如何處理空模板參數包擴展引起的未使用的警告?

template <std::size_t... I> 
auto func1(std::index_sequence<I...>) 
{ 
    auto var = get_tuple(); 
    return func2(std::get<I>(var)...); 
} 

auto a = func1(std::make_index_sequence<0>()); 

參見live example(嘗試改變元組在第4行中,加入內<一個int>看到警告消失)。 我知道我可以添加一條(void)var;行來使警告消失,但對我來說感覺很髒,特別是當函數實際上只是一行時。 我也不想全局禁用此警告,因爲它有時會提供洞察力。

這個問題的一個類似的表現是變量用於lambda捕獲。在這種情況下,海灣合作委員會吐出任何警告,而鐺抱怨(我想不用的拉姆達捕捉GCC從來沒有實現過警告):

template <std::size_t... I> 
auto func1(std::index_sequence<I...>) 
{ 
    auto var = get_tuple(); 
    auto my_lambda = [var](){ 
    return func2(std::get<I>(var)...); 
    }; 
    return my_lambda(); 
} 

auto a = func1(std::make_index_sequence<0>()); 

clang example

+2

使用鐺和文件到GCC的bug報告:P – Rakete1111

+2

您仍然可以'編譯推/ pop'圍繞該功能禁用警告。但'static_cast (var);'似乎更好的解決方法。 – Jarod42

+0

'return func2(std :: get (get_tuple())...);'? – nwp

回答

3

這似乎是在GCC編譯器錯誤。最簡單的解決方法是,以紀念var[[gnu::unused]]

template <std::size_t... I> 
auto func1(std::index_sequence<I...>) 
{ 
    auto var [[gnu::unused]] = get_tuple(); 
    return func2(std::get<I>(var)...); 
} 

如果你是外力使用編譯器不能識別[[gnu::unused]],你可以僞造使用了static_cast<void>變量:

template <std::size_t... I> 
auto func1(std::index_sequence<I...>) 
{ 
    auto var = get_tuple(); 
    static_cast<void>(var); 
    return func2(std::get<I>(var)...); 
} 
+0

這種破壞可移植性嗎? –

+0

如果某個屬性無法識別,編譯器會忽略它。 GCC和LLVM都支持'[[gnu :: unused]]'。 –

+3

不會識別的屬性也會吐出警告嗎? [像這樣](https://godbolt.org/g/oz9cwR) –

-1

也許有是其他問題,但是...根據您在編譯器資源管理器中鏈接的代碼,您的varstd::tuple<>;這是一個std::tuple零組件。

如果我沒有錯,std::get<Num>(std::tuple<Ts..>)僅在Num[0,sizeof...(Ts));在這種情況下在[0, 0),這是一個空的間隔。

我想你的代碼(當var被定義爲std::tuple<>)生病了。所以我想這個警告是正確的(因爲沒有使用var的情況),但沒有警告真正的問題。

這是不同的,當var被定義爲std::tuple<int>var當所有I都等於零被正確使用,所以var是使用(潛在的)和,如你觀察到的,警告消失。

+2

但是如果'var'是空的,代碼擴展爲空,不是嗎? – Rakete1111

+0

@ Rakete1111 - 我想你是對的,但(如果我沒有錯)'var'永遠不會被使用;當'sizeof ...(I)'爲零時,何時磨碎。所以警告信息。當OP在'std :: tuple '中變換'var'時,警告消失,因爲(如果我沒有錯的話)會有'var'正確使用的情況:when(only only)all '我'是零。 – max66

+0

同意,代碼使用'var',所以警告是錯誤的。不知道我理解你的最後一點。 – Rakete1111

2

(void)var;抑制未使用的警告在每一個編譯器我用:

template <std::size_t... I> 
auto func1(std::index_sequence<I...>) 
{ 
    auto var = get_tuple(); 
    (void)var; 
    return func2(std::get<I>(var)...); 
} 
auto a = func1(std::make_index_sequence<0>()); 

(void)variable;具有零度運行時間的影響。

7

如果你可以使用C++ 17的[[maybe_unused]]屬性是IMO清晰的解決方案:

[[maybe_unused]] 
auto tuple = get_tuple(); 
+0

當變量在lambda中時,你將如何使用它capture:https://godbolt.org/g/CrwNhM – dcmm88

+0

@ dcmm88提交錯誤,因爲你正在使用'var'。這是一個解決方法:https://godbolt.org/g/xLzKnB – Rakete1111

5

var的確不是空包使用。 它是打算?編譯器只能猜測。

鑑於鏘比空包是一種用法,gcc選擇相反。

您可以靜默以不同的方式作爲警告:

  • 屬性[[maybe_unused]](C++ 17)
  • 鑄造voidstatic_cast<void>(arg)
  • 或類似(template <typename T> void unused_var(T&&){}然後unused_var(var))。
  • 創造重載:

    auto func1(std::index_sequence<>) 
    { 
        return func2(); 
    } 
    
    template <std::size_t... I> 
    auto func1(std::index_sequence<I...>) 
    { 
        auto var = get_tuple(); 
        return func2(std::get<I>(var)...); 
    } 
    

    或C++ 17

    template <std::size_t... I> 
    auto func1(std::index_sequence<I...>) 
    { 
        if constexpr (sizeof ...(I) == 0) { 
         return func2(); 
        } else { 
         auto var = get_tuple(); 
         return func2(std::get<I>(var)...); 
        } 
    } 
    
+2

C風格強制轉換爲void是C風格強制轉換可能不會做壞行爲的少數情況之一。另外,'unused_var'可能會無意中強迫ODR存在一個變量。 – Yakk