C++11 如何处理空模板参数包扩展导致的未使用警告?

C++11 如何处理空模板参数包扩展导致的未使用警告?,c++11,gcc,clang,variadic-templates,compiler-warnings,C++11,Gcc,Clang,Variadic Templates,Compiler Warnings,我一直面临的一个问题是编译器抱怨一个未使用的变量,即使使用了该变量,但它只在参数包扩展中使用,而对于特定的实例化,该扩展恰好为空。 例如: 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_ind

我一直面临的一个问题是编译器抱怨一个未使用的变量,即使使用了该变量,但它只在参数包扩展中使用,而对于特定的实例化,该扩展恰好为空。 例如:

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>());

这似乎是GCC中的一个编译器错误。最简单的解决方法是使用
[[gnu::unused]]
标记
var

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

也许还有其他问题,但是。。。根据您在编译器资源管理器中链接的代码,您的
var
是一个
std::tuple
;这是一个零组件的
std::tuple

如果我没有错的话,
std::get(std::tuple)
仅在
Num
位于
[0,sizeof…(Ts))
中时定义;在本例中,在
[0,0)
中,这是一个空间隔

我假设您的代码(当
var
被定义为
std::tuple
时)格式不正确。因此我假设警告是正确的(因为使用
var
时没有案例),但没有警告真正的问题

var
被定义为
std::tuple
时,情况就不同了:
var
在所有
I
都等于零时被正确使用,因此
var
被(潜在地)使用,正如您所观察到的,警告消失了。

(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>());
模板
自动功能1(标准::索引\u序列)
{
auto var=get_tuple();
(无效)var;
返回func2(std::get(var)…);
}
自动a=func1(std::make_index_sequence());

(void)变量;
的运行时效果为零。

如果可以使用C++17,
[[maybe_unused]]
属性是最清晰的解决方案:

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

var
确实不能与空包一起使用。 这是故意的吗?编译器只能猜测

而CLANG考虑比空包是一种用法,GCC选择相反。

您可以通过以下不同方式使警告静音:


  • 属性
    [[可能未使用]]
    (C++17)
  • 强制转换为无效(
    静态强制转换(arg)
  • 或类似(
    template 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)...);
    }
    
    自动功能1(标准::索引\u序列)
    {
    返回func2();
    }
    模板
    自动功能1(标准::索引\u序列)
    {
    auto var=get_tuple();
    返回func2(std::get(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)...);
        }
    }
    
    模板
    自动功能1(标准::索引\u序列)
    {
    如果constexpr(sizeof…(I)==0){
    返回func2();
    }否则{
    auto var=get_tuple();
    返回func2(std::get(var)…);
    }
    }
    


使用clang并向gcc提交错误报告:pyu仍然可以
pragma push/pop
绕过函数来禁用警告。但是
static_cast(var);
似乎是更好的解决方法。如何
返回func2(std::get(get_tuple())…)
?@Jarod42不太明显的是,这是为了使警告静音,而不是强迫读取
var
或其他文件的糟糕工作weirdness@nwp这不是要多次执行
get\u tuple
,它可能会也可能不会总是返回相同的内容?如果它执行了大量操作,也可能会导致性能问题。Wi这会破坏可移植性吗?如果一个属性无法识别,编译器会忽略它。GCC和LLVM都支持
[[gnu::unused]]
。无法识别的属性不会也发出警告吗?取决于编译器设置:-)第二个解决方案(我知道的唯一一个解决方案是如何使其适用于lambda捕获:),这不是在阻止优化器从编译器输出中完全消除var吗?但是如果
var
为空,代码将扩展为零,否?@Rakete1111-我想你是对的,但是(如果我没有错)
var
从未被使用过;当
sizeof…(I)
为零,when为grater。因此警告消息。当
std::tuple
中的OP转换
var
时,警告消失,因为(一如既往:如果我没有错的话)存在正确使用
var
的情况:when(仅当)所有
I
均为零。同意,代码使用
var
,因此警告是错误的。我不确定我是否理解您的最后一点。@raket1111-我的最后一点是,如果
var
std::tuple
(警告情况),
var
从未使用过(同样当
sizeof…(I)
大于零时)当
var
std::tuple
(无警告情况)时,当所有
I
都等于零时使用
var
(正确!)。因此(如果我没有错,像往常一样)编译器是正确的(在两种情况下),但在第一种情况下,真正的问题是另一个(调用
std::get(var))
var
std::tuple
在任何情况下都是错误的)@max66是的,它抱怨未使用的变量的原因是参数包扩展为空。因此
var
在扩展后并没有真正使用。但我的全部观点是警告对我来说是无用的。请注意,clang并没有抱怨完全相同的代码(尽管它在另一种情况下抱怨)。此外,我的代码中没有UB。当
var
std::tuple
时,
std::get(var)
没有任何错误,因为它是参数包扩展表达式的一部分,计算结果为空。因此从来没有像
std::get(var)这样的调用
正在生成。当变量在lambda捕获中时,您将如何使用它:@dcmm88文件存在错误,因为您使用的是
var
。这里有一个解决方法:c样式强制转换为void是c样式强制转换可以证明不会产生不良行为的少数情况之一。此外,
未使用的\u var
可能会意外地强制ODR存在一个var如果不小心使用,则不可用。
[[可能未使用]]
在7之前不受GCC支持
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)...);
}
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)...);
    }
}