jww
jww

Reputation: 102346

How to use UNUSED macro to silence warning within a CONSTEXPR function?

I'm experiencing an issue where a static member function uses an UNUSED macro to silence compiler warnings. When the macro is in effect, it causes GCC and Clang to reject the function as a constexpr. Here's the test case:

$ cat test.cxx
#include <iostream>
#include <stdint.h>

#define UNUSED(x) ((void)x)

template <unsigned int N>
class Foo
{
public:
    enum {MIN_N=N}; enum {MAX_N=N}; enum {DEF_N=N};
    constexpr static size_t GetValidN(size_t n)
    {
        UNUSED(n); return DEF_N;
    }
};

class Bar : public Foo<16>
{
public:
    Bar(size_t n) : m_n(GetValidN(n)) {}
    size_t m_n;
};

int main(int argc, char* argv[])
{
    Bar b(10);
    return 0;
}

Here's the GCC error message:

$ g++ -std=c++11 test.cxx -o test.exe
test.cxx: In instantiation of ‘static constexpr size_t Foo<N>::GetValidN(size_t) [with unsigned int N = 16u; size_t = long unsigned int]’:
test.cxx:22:25:   required from here
test.cxx:16:5: error: body of constexpr function ‘static constexpr size_t Foo<N>::GetValidN(size_t) [with unsigned int N = 16u; size_t = long unsigned int]’ not a return-statement
     }
     ^

If I remove the use of UNUSED, then the source file compiles as expected:

constexpr static size_t GetValidN(size_t n)
{
    return DEF_N;
}

As far as I know, the #define UNUSED(x) ((void)x) is the only portable way to suppress unused variable warnings. I dread removing UNUSED because the macro suppresses thousands of warnings in a non-trivial C++ project with lots of interfaces. I'm not even sure I can remove UNUSED because of governance issues related to auditing and C&A.

How can I make the UNUSED macro work and play well with constexpr?


Clang produces a more helpful error message:

$ clang++ -std=c++11 test.cxx -o test.exe
test.cxx:15:2: warning: use of this statement in a constexpr function is a C++14
      extension [-Wc++14-extensions]
        UNUSED(n); return DEF_N;
        ^
test.cxx:4:19: note: expanded from macro 'UNUSED'
#define UNUSED(x) ((void)x)
                  ^
1 warning generated.

Another twist when moving from the clean room to production: Doxygen. This is closer to what happens in practice, so we can't omit the variable name.

//! \brief Returns a valid N
//! \param n a value to determine a valid N
//! \returns a valid N
constexpr static size_t GetValidN(size_t n)
{
    return DEF_N;
}

Upvotes: 3

Views: 1098

Answers (3)

skypjack
skypjack

Reputation: 50550

In C++11 you have some limitations on the body of a constexpr function.

In your specific case you can use the comma operator to overcome them:

constexpr static size_t GetValidN(size_t n)
{
    return UNUSED(n), DEF_N;
}

In C++14, your function is ok as it is.

Upvotes: 2

user2176127
user2176127

Reputation:

The simplest solution would be to just comment out the n as kfsone mentioned.

In C++17 you could even do it like this:

constexpr static size_t GetValidN([[maybe_unused]] size_t n)
{
    return DEF_N;
}

For more information see http://en.cppreference.com/w/cpp/language/attributes

I'm not sure if this is a stylistically sane solution, hopefully IDEs will find a way to make it look less ugly.

Upvotes: 0

kfsone
kfsone

Reputation: 24269

You could simply avoid giving the argument a name, or comment it out:

constexpr size_t DEF_N = 42;

constexpr static size_t GetValidN(size_t /*n*/)
{
    return DEF_N;
}

live demo

Upvotes: 3

Related Questions