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

时间:2017-09-28 15:30:21

标签: 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_index_sequence<0>());

请参阅live example(尝试更改第4行的元组,在内部添加一个int&lt;&gt;以查看警告消失)。 我知道我可以添加(void)var;行来使警告消失,但对我来说感觉很脏,特别是当函数实际上只是一行时。 我也不想在全球范围内禁用此警告,因为它确实提供了有时的见解。

此问题的类似表现形式是在lambda捕获中使用变量时。在这种情况下,gcc没有发出警告,而clang抱怨(我认为gcc从未实现过关于未使用的lambda捕获的警告):

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

5 个答案:

答案 0 :(得分:7)

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

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

答案 1 :(得分:5)

var确实不适用于空包装。 有意吗?编译器只能猜测。

虽然clang认为空包是一种用法,但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 :(得分: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)...);
}

答案 3 :(得分: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;没有运行时效果。

答案 4 :(得分:-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,因此for i in enumerate(s1): c1 = int(s1[i] < 0) c2 = int(s1[i]>s2[i]) s3[i] = c1*0 + int(not c1)*( s1[i]*c2 + s2[i]*(not c2) ) 是(可能)如你所见,警告消失了。