Reputation: 1515
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>());
Upvotes: 13
Views: 2212
Reputation: 275585
(void)var;
suppressed unused warnings in every compiler I have used:
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;
has zero run time effects.
Upvotes: 2
Reputation: 217573
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:
[[maybe_unused]]
(C++17)void
(static_cast<void>(arg)
)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)...);
}
}
Upvotes: 5
Reputation: 66210
Maybe there are other problems but... according the code you linked in compiler explorer, your var
is a std::tuple<>
; that is a std::tuple
with zero components.
If I'm not wrong, std::get<Num>(std::tuple<Ts..>)
is defined only when Num
is in [0,sizeof...(Ts))
; in this case in [0, 0)
, that is an empty interval.
I suppose that your code (when var
is defined as std::tuple<>
) is ill formed. So I suppose that the warning is correct (because there isn't cases when var
is used) but doesn't warn about the real problem.
It's different when var
is defined as std::tuple<int>
: var
is correctly used when all I
are equal to zero, so var
is (potentially) used and, as you observed, the warning disappears.
Upvotes: -1
Reputation: 48978
If you can use C++17, the [[maybe_unused]]
attribute is the clearest solution IMO:
[[maybe_unused]]
auto tuple = get_tuple();
Upvotes: 7
Reputation: 27643
This seems to be a compiler bug in GCC. The easiest workaround is to mark var
with [[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)...);
}
If you are force to use compilers that don't recognize [[gnu::unused]]
, you can fake use the variable with a 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)...);
}
Upvotes: 3