5

Consider this classic example:

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N]) noexcept { return N; }

Now this works fine, but there is one annoyance, gcc gives a warning:

warning: unused parameter ‘array’ [-Wunused-parameter]

Known solutions:

  • Doesn't work: If I add the classic (void)arr; to the function, I get error: body of constexpr function ‘...‘ not a return-statement.
  • Unsatisfactory: I can have arraySize(T (&)[N]), but I want to name the argument for two reasons:
    1. It makes compiler error message more understandable.
    2. More subjectively, I think it makes the code clearer, especially to those who don't live and breathe that syntax.
  • Not good: In this particular example, I could also return sizeof(array)/sizeof(array[0]);, but this approach is not universal solution, and also I think return N; is much nicer, definitely easier on the eye.
  • Good but not always possible: switch to using C++14 and compiler which supports it fully. Then constexpr function body like { (void)array; return N; } is allowed.

How can I get rid of the unused parameter warning nicely, when using C++11?

hyde
  • 60,639
  • 21
  • 115
  • 176
  • I'm not at my laptop, but by simply using `arraySize(T*)` (with no name for you don't need it) does not solve? Of course, with the right type, sorry if I cannot have a try for you... – skypjack Oct 25 '15 at 07:45
  • @skypjack As I understand it, a reference to array is required. Otherwise compiler can't give `N` automatically. That's why `arraySize(T[N])` won't work either (tested, won't compile without explicitly giving `N` as template argument when calling the function). – hyde Oct 25 '15 at 07:47
  • 1
    `arraySize(T(&)[N])`? This should work, but I'm not sure about the warning, for I cannot try. If it's fine, I'll put it in a response. – skypjack Oct 25 '15 at 07:54
  • 1
    Oh, sorry, my fault. Well, if you insist in giving a name to the parameter, the compiler will continue to give a warning, unless you convince it about your solution bullet 2... :-) ... Otherwise, use something like `return arr ? N : N;`, I'm quite confident that the compiler will get rid of it with no performance issue at runtime. – skypjack Oct 25 '15 at 08:01
  • 3
    @hyde how about `return (void)array, N;`? – The Paramagnetic Croissant Oct 25 '15 at 08:04
  • which compiler version are you using? I can't reproduce the warning here: http://melpon.org/wandbox/permlink/P5j7jVUyGy2XxO1t – m.s. Oct 25 '15 at 08:04
  • 1
    It's curious: if C++14 option is off, then using `auto` without a trailing return type should not compile; if C++14 is on, then `(void)arr;` should be fine. – cpplearner Oct 25 '15 at 08:05
  • @cpplearner I edited the question to be proper C++11. But I'll check my compiler options, I think this is *gcc* in C++11 mode, but with some extension enabled. Anyway, "switch to C++14 and use void cast" would be an excellent answer :) – hyde Oct 25 '15 at 08:07
  • @m.s. *gcc 4.8.4* of Ubuntu 14.04, using `-std=C++1y` option, so yeah... I don't have a newer distro handy right here and now, but I assume best solution is indeed "switch to a newer compiler which has full C++14 support". – hyde Oct 25 '15 at 08:19
  • @hyde Great, added an answer. – The Paramagnetic Croissant Oct 25 '15 at 09:19

7 Answers7

5

Try this. I use this method sometimes

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }
fnc12
  • 2,241
  • 1
  • 21
  • 27
  • 2
    did you read either the question or the answer from @skypjack? – m.s. Oct 25 '15 at 08:23
  • @m.s. Yeah I didn't read the answer to the end. I will correct or delete my answer in ten minutes – fnc12 Oct 25 '15 at 08:39
  • 1
    I like this solution the most, because it does not introduce any unneeded logic that may confuse the reader like the other answers do. – Sopel Sep 10 '17 at 09:42
4

I'd suggest the following (ab)use of the comma operator:

return (void)array, N;
  • 1
    Within the constraints of the question, I like this the best, as it shouldn't actually evaluate anything. Probably wise to add a comment like `// void cast with comma operator for C++11 compatiblity` – hyde Oct 25 '15 at 12:04
  • @hyde yes, documenting the (relatively) weird returned expression with a comment is probably a good idea. – The Paramagnetic Croissant Oct 25 '15 at 12:30
4

For new googlers:

C++17 adds a [[maybe_unused]] attribute which could be used like this:

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N] [[maybe_unused]]) noexcept { return N; }
ted
  • 4,791
  • 5
  • 38
  • 84
2

The best solution is the one forbidden with the second point, that is to use T(&)[N].

Another possible approach, as from the comment, is to use the following return value:

return array ? N : N;

I'm quite sure that the compiler will get rid of it and there will be no performance issue at runtime.

skypjack
  • 49,335
  • 19
  • 95
  • 187
  • If you want to suppress the compiler warning, then use a #pragma to suppress it. Referencing a parameter for no reason than to suppress a compiler warning is the opposite of writing clear readable code. – Ryan Bemrose Oct 25 '15 at 09:01
  • 1
    I'd rather put the sole type with no variable name, that is far clearer than a pragma, but he has some constraints (see the question) and this one is a possible and portable solution, nothing more. – skypjack Oct 25 '15 at 09:03
1

As @fnc12 and @skypjack both point out, the idiomatic way to silence an unused parameter compiler warning is to not give a name to the parameter.

constexpr std::size_t arraySize(T (& /*array*/ )[N]) noexcept { return N; }

Using the /**/ comments solves the readability objection. It doesn't fix the name in a compiler message, but I would argue that the most likely situation to arise from this is "undeclared identifier", which is pretty easy and obvious to solve once you notice the identifier is commented.

If you're really dead set against the idiomatic way, then just suppress the warning (locally if your compiler allows it).

Suppressing warnings in GCC using #pragma GCC diagnostic.

Suppressing warnings in Visual Studio using #pragma warning suppress

I recommend against adding "dummy" references to the code to shut up the compiler. Referencing an otherwise unused parameter for no reason than to suppress a compiler warning needlessly adds complexity to your code, and can confuse future maintainers as to why it's there.

Ryan Bemrose
  • 9,018
  • 1
  • 41
  • 54
  • 1
    Actually, when putting the parameter name in comments, at least *gcc* shows it, so it actually helps there too (of course looks a bit ugly...). And I definitely agree with removing unused parameter name from function *definition*. But IMO declarations should have them, and here definition and declaration are the same. – hyde Oct 25 '15 at 09:21
1

The unnamed argument is the right solution.

So you may use a intermediate function:

template <typename T>
constexpr void avoid_warning_for_unused_parameter(T&&) noexcept{}

and then:

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N]) noexcept
{
    avoid_warning_for_unused_parameter(array);
    return N;
}

For C++11, you have to hack little more:

template <typename... Ts>
constexpr auto return_first_and_avoid_warning_for_unused_parameters(T&&t, Ts&&) noexcept
-> decltype(t)
{
    return t;
}

template <typename T, std::size_t N>
constexpr std::size_t arraySize(T (&array)[N]) noexcept
{
    return return_first_and_avoid_warning_for_unused_parameters(N, array);
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • This is not much different from just using the traditional `(void)` cast, as this also *requires C++14*. I can understand the point of making explicitly named "unused" function (or macro), but I personally would prefer plain old traditional `(void)` cast to the clutter of an extra function, as it is a pretty well established idiom. YMMV. – hyde Oct 25 '15 at 11:49
  • 1
    @hyde: according to http://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/, `(void) array` doesn't work for all compilers. – Jarod42 Oct 26 '15 at 08:14
1

gcc provides the unused attribute which can be used as follows:

constexpr std::size_t arraySize(__attribute__((unused)) T (&array)[N]) noexcept { return N; }
                                ^^^^^^^^^^^^^^^^^^^^^^^

Ben Deane recently tweatted about a C++11 way to suppress this warning using lambdas which combined with the comma operator would look something like this:

#define UNUSED(x) [&x]{}()

//...

return UNUSED(array), N;
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740