У меня возникла проблема, когда статическая функция-член использует UNUSED
макрос, чтобы заставить замолчать предупреждения компилятора. Когда макрос действует, он заставляет GCC и Clang отклонить функцию как constexpr
, Вот контрольный пример:
$ 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;
}
Вот сообщение об ошибке GCC:
$ 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
}
^
Если я Удалить использование UNUSED
Затем исходный файл компилируется, как и ожидалось:
constexpr static size_t GetValidN(size_t n)
{
return DEF_N;
}
Насколько я знаю, #define UNUSED(x) ((void)x)
это единственный портативный способ подавления unused variable
предупреждения. Я боюсь удалить UNUSED
потому что макрос подавляет тысячи предупреждений в нетривиальном проекте C ++ с большим количеством интерфейсов. Я даже не уверен, что смогу удалить UNUSED
из-за вопросов управления, связанных с аудитом и C&A.
Как я могу сделать UNUSED
макро работа и хорошо играть с constexpr
?
Clang выдает более полезное сообщение об ошибке:
$ 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.
Еще один поворот при переходе от чистой комнаты к производству: Doxygen. Это ближе к тому, что происходит на практике, поэтому мы не можем опустить имя переменной.
//! \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;
}
В C ++ 11 у вас есть некоторые ограничения на тело constexpr
функция.
В вашем конкретном случае вы можете использовать оператор запятой для их преодоления:
constexpr static size_t GetValidN(size_t n)
{
return UNUSED(n), DEF_N;
}
В C ++ 14 с вашей функцией все в порядке.
Вы можете просто не давать аргументу имя или комментировать его:
constexpr size_t DEF_N = 42;
constexpr static size_t GetValidN(size_t /*n*/)
{
return DEF_N;
}
Самым простым решением было бы просто закомментировать n, как упомянуто kfsone.
В C ++ 17 вы могли бы даже сделать это так:
constexpr static size_t GetValidN([[maybe_unused]] size_t n)
{
return DEF_N;
}
Для получения дополнительной информации см. http://en.cppreference.com/w/cpp/language/attributes
Я не уверен, что это стилистически вменяемое решение, надеюсь, IDE найдут способ сделать его менее уродливым.