2015-10-25 2 views
5

Рассмотрим классический пример:Как отметить неиспользуемый параметр функции constexpr?

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

Теперь это работает отлично, но есть одна неприятность, НКУ выдает предупреждение:

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

Известные решения:

  • Безразлично» t: Если я добавлю классику (void)arr; к функции, я получаю error: body of constexpr function ‘...‘ not a return-statement.
  • Неудовлетворительно: Я могу иметь arraySize(T (&)[N]), но я хочу назвать аргумент по двум причинам:
    1. Это делает сообщение об ошибке компилятора более понятным.
    2. Более субъективно, я думаю, что он делает код более понятным, особенно тем, кто не живет и не дышит этим синтаксисом.
  • Не хорошо: В этом конкретном примере, я мог бы также return sizeof(array)/sizeof(array[0]);, но этот подход не является универсальным решением, а также я думаю return N; гораздо лучше, безусловно, легче на глаз.
  • Хорошо, но не всегда возможно: переключитесь на использование C++ 14 и компилятора, который полностью поддерживает его. Тогда допускается тело функции constexpr, например { (void)array; return N; }.

Как я могу избавиться от неиспользуемого параметра предупреждения красиво, при использовании 11 C++?

+0

Я не на своем ноутбуке, а просто используя 'arraySize (T *)' (без имени для вас не нужен) не решает? Конечно, с правильным типом, извините, если я не могу попробовать вас ... – skypjack

+0

@skypjack Как я понимаю, требуется ссылка на массив. В противном случае компилятор не может автоматически выдавать 'N'. Вот почему 'arraySize (T [N])' тоже не будет работать (проверено, не будет компилироваться без явного указания 'N' в качестве аргумента шаблона при вызове функции). – hyde

+1

'arraySize (T (&) [N])'? Это должно работать, но я не уверен в предупреждении, потому что я не могу попробовать. Если все в порядке, я отвечу в ответ. – skypjack

ответ

4

Я хотел бы предложить следующее (AB) использование оператора запятой:

return (void)array, N; 
+1

В рамках ограничений вопроса мне нравится это лучше всего, так как это не должно фактически ничего оценивать. Вероятно, разумно добавить комментарий вроде '// void cast с оператором запятой для C++ 11 compatiblity' – hyde

+0

@hyde yes, документирование (относительно) странного возвращаемого выражения с комментарием, вероятно, хорошая идея. –

2

Лучшим решением является тот, который запрещен второй точкой, то есть использовать T(&)[N].

Другой возможный подход, с комментарием, чтобы использовать следующее значение возврата:

return array ? N : N; 

Я совершенно уверен, что компилятор будет избавиться от него, и не будет никаких проблем с производительностью во время выполнения ,

+0

Если вы хотите отключить предупреждение компилятора, используйте #pragma для его подавления.Ссылка на параметр без каких-либо причин, кроме как подавить предупреждение компилятора, является противоположностью написанию четкого читаемого кода. –

+1

Я предпочел бы поставить единственный тип без имени переменной, что намного яснее, чем прагма, но у него есть некоторые ограничения (см. Вопрос), и это одно из возможных и портативных решений, не более того. – skypjack

4

Попробуйте это. Я использую этот метод иногда

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

Вы читали вопрос или ответ от @skypjack? –

+0

@ м.с. Да, я не прочитал ответ до конца. Я исправлю или удалю свой ответ за десять минут. – fnc12

+1

Мне нравится это решение больше всего, потому что оно не вводит никакой ненужной логики, которая может смутить читателя, как и другие ответы. – Sopel

1

As @ fnc12 и @skypjack как указывают, идиоматических способ заглушить неиспользуемый предупреждение компилятора параметр не дать имя параметра.

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

Использование /**/ комментарии решает читаемость возражения. Он не фиксирует имя в сообщении компилятора, но я бы сказал, что наиболее вероятная ситуация, возникающая из этого, - это «необъявленный идентификатор», который довольно легко и очевидно решить после того, как вы заметите, что идентификатор прокомментирован.

Если вы действительно мертвы по отношению к идиоматическому пути, тогда просто подавите предупреждение (локально, если ваш компилятор разрешает это).

Suppressing warnings in GCC using #pragma GCC diagnostic.

Suppressing warnings in Visual Studio using #pragma warning suppress

Я рекомендую против добавления «фиктивные» ссылки на код, чтобы заткнуться компилятор. Если ссылаться на неиспользуемый параметр по какой-либо причине, кроме как подавить предупреждение о компиляторе, то вам ненужно добавляется сложность вашего кода и может запутать будущих сопровождающих относительно того, почему он есть.

+1

Собственно, при пометке имени параметра в комментариях, по крайней мере, * gcc * показывает его, поэтому он действительно помогает там (конечно, выглядит немного уродливо ...). И я определенно согласен с удалением неиспользуемого имени параметра из функции * definition *. Но объявления ИМО должны иметь их, и здесь определение и декларация одинаковы. – hyde

1

Неназванный аргументом является правильным решением.

Таким образом, вы можете использовать промежуточную функцию:

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

, а затем:

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

Для C++ 11, вы должны взломать немного больше:

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); 
} 
+0

Это не сильно отличается от обычного использования '(void)' cast, так как это также требует C++ 14 *. Я могу понять, что нужно явно указать «неиспользуемую» функцию (или макрос), но я лично предпочел бы просто старый традиционный '(void)' приведение к беспорядку дополнительной функции, поскольку это довольно хорошо установленная идиома. YMMV. – hyde

+1

@hyde: согласно http://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/, '(void) array' не работает для всех компиляторов. – Jarod42

+0

Интересное обсуждение там, полезно знать! – hyde

1

GCC содержит unused attribute, который может использоваться следующим образом:

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

Ben Deane recently tweatted about a C++11 way подавить это предупреждение, используя лямбды, которые в сочетании с оператором запятой будет выглядеть примерно так:

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

//... 

return UNUSED(array), N; 
2

Для новых Googlers:

C++ 17 добавляет атрибут, который может [[maybe_unused]] можно использовать следующим образом:

template <typename T, std::size_t N> 
constexpr std::size_t arraySize(T (&array)[N] [[maybe_unused]]) noexcept { return N; } 
Смежные вопросы