如何处理空模板参数包扩展引起的未使用的警告?

问题描述:

即使使用了变量,我仍然面临的一个问题是编译器会抱怨一个未使用的变量,但它只用于参数包扩展中,对于特定的实例而言,它只是空的。 例如:如何处理空模板参数包扩展引起的未使用的警告?

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

这似乎是在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) –

也许有是其他问题,但是...根据您在编译器资源管理器中链接的代码,您的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

(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;具有零度运行时间的影响。

如果你可以使用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

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