Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle unused warnings caused by empty template parameter pack expansions?

An issue I keep facing is one where the compiler complains about an unused variable, even though the variable is used, but it's only used inside a parameter pack expansion that happens to be empty for a specific instantiation. For example:

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

See live example (try changing the tuple at line 4, by adding an int inside <> to see the warning go away). I know I could add a (void)var; line to make the warning go away, but it feels dirty to me, especially when the function is actually just a single line. I also don't want to disable this warning globally, because it does provide insight sometimes.

A similar manifestation of this issue is when the variable is used in a lambda capture. In this case, gcc spits no warning, while clang complains (I think gcc never implemented a warning about unused lambda captures):

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

like image 255
dcmm88 Avatar asked Sep 28 '17 15:09

dcmm88


2 Answers

If you can use C++17, the [[maybe_unused]] attribute is the clearest solution IMO:

[[maybe_unused]]
auto tuple = get_tuple();
like image 161
Rakete1111 Avatar answered Sep 28 '22 05:09

Rakete1111


var is indeed not use with empty pack. Is it intended ? compiler can only guess.

Whereas clang consider than empty pack is a usage, gcc chooses the contrary.

You can silent the warning in different ways as:

  • attribute [[maybe_unused]] (C++17)
  • casting to void (static_cast<void>(arg))
  • or similar (template <typename T> void unused_var(T&&){} and then unused_var(var)).
  • creating overloads:

    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)...);
    }
    

    or in 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)...);
        }
    }
    
like image 33
Jarod42 Avatar answered Sep 28 '22 07:09

Jarod42