std::ignore для игнорирования неиспользуемой переменной

Это хороший подход к использованию std::ignore для игнорирования неиспользуемых переменных?

Предположим, у меня есть такая функция:

void func(int i)
{
   //for some reason, I don't need i anymore but I cannot change signature of function    
   std::ignore = i; 
}

Дополнительная информация

Это был один пример, и в некоторых ответах предлагалось использовать анонимные переменные. Но как бы я сделал это для других случаев, таких как:

int Thread_UnSafe_func_returnSomething():
void func()
{
   // To make it thread safe
   // Also it is required to call only once
   static int i = Thread_UnSafe_func_returnSomething();

   std::ignore = i;
}

7 ответов

Решение

В таком случае просто не пишите имя переменной:

void func(int /*i*/)
{
    ...
}

Ответ @ Хейта хорош, но использует последнюю версию C++, которая не всегда доступна. Не писать имя переменной - это старое соглашение, сообщающее компилятору, что переменная вам на самом деле не нужна.

Для обновленного вопроса я бы пошел на статический экземпляр класса с необходимой инициализацией в конструкторе. Я говорю инициализация, потому что единственная причина, по которой я могу сделать такую ​​функцию, - это инициализация некоторого глобального объекта.

class SomethingInitializer {
public:
    SomethingInitializer() {
        func_returnSomething();
    }
    ~SomethingInitializer() {
        // Note, that when you initialize something it is a good practice to deinitialize it at the end, and here is a proper place for that.
    }
};

void func() {
    static SomethingInitializer initializer;
}

Это решение имеет небольшой бонус: SomethingInitializer соответствует RAII. Поэтому, когда приложение завершается, вызывается деструктор, который может выполнить деинициализацию.

Обратите внимание, что компилятор знает, что классы могут делать что-то полезное в конструкторе и деструкторе, поэтому он не будет жаловаться на неиспользуемую переменную.

std::ignore может работать, но он предназначен для кортежей. Таким образом, вам нужно включить заголовок кортежа, и кто знает, какие операции выполняются для назначения. Это также может сломаться в другой версии C++, потому что она никогда не была документирована для использования таким образом.

Лучшим способом для этого является атрибут C++17 [[maybe_unused]]

void func([[maybe_unused]] int i)
{
}

Он размещает объявление прямо в объявлении переменной, поэтому вам не нужно объявлять его в дополнительной строке / выражении.

То же самое можно использовать для локальных (и локально-статических) переменных.

...
[[maybe_unused]] static int a = something();
...

А также для многих других:

Появляется в объявлении класса, typedef, переменной, нестатического члена данных, функции, перечисления или перечислителя. Если компилятор выдает предупреждения о неиспользуемых объектах, это предупреждение подавляется для любого объекта, объявленного Maybe_unused.

См. http://en.cppreference.com/w/cpp/language/attributes

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

Да, это возможно, но (по крайней мере, с помощью clang) вы получите предупреждения в случае использования maybe_unused объявленные переменные.

std::ignore не предназначался для этой цели:

Объект неопределенного типа, так что ему может быть присвоено любое значение без эффекта. Предназначен для использования с std:: tie при распаковке std:: tuple, в качестве заполнителя для аргументов, которые не используются.


Я бы посоветовал вам не делать то, о чем вы думаете, так как в реальном большом проекте это приведет к тому, что код будет сложнее поддерживать, где можно было бы посмотреть на прототип функции, увидеть, что он принимает аргумент int i, но функция не нуждается в этом на самом деле - не чувствует себя хорошо, не так ли?:)

Как альтернатива, без удаления i Исходя из подписи (как может потребоваться некоторым инструментам документации), есть несколько способов сделать предупреждение молчанием:

void func(int i)
{
   static_cast<void>(i); // Silent warning for unused variable
}

Он не является полностью переносимым, но это предупреждает большинство компиляторов.

Чистый способ - создать для этого отдельную функцию:

template <typename T>
void Unused(T&& /*No name*/) { /*Empty*/ }

а потом

void func(int i)
{
   Unused(i); // Silent warning for unused variable
}

Я думаю, что у вас есть проблема XY здесь. Вы действительно не заботитесь о том, как игнорировать статические переменные; Вы просто хотите вызвать функцию один раз (и только один раз) потокобезопасным, реентерабельным способом.

На что я говорю: вы слышали о std::call_once? Вы должны переписать свой метод как

#include <mutex>

int Thread_UnSafe_func_returnSomething();
void func(void)
{
      //To make it thread safe
     static std::once_flag initComplete;
     std::call_once(initComplete, func_returnSomething);
 }

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

auto func(int i) -> decltype(void(i)) {}
int main() {}

Если у вас есть более одной переменной, вы можете перечислить их все:

auto func(int i, int j) -> decltype(void(i), void(j)) {}
int main() {}

И вы все равно можете объявить предпочитаемый тип возврата, если void это не то что ты хочешь

auto func(int i) -> decltype(void(i), int{}) { return 42; }
int main() {}

Преимущества этого решения:

  • Имя переменной сохраняется: как уже упоминалось другими, не давать имя переменной не может быть вариантом (из-за вашей системы документации, в качестве примера).

  • Вы не будете загрязнять свое функциональное тело бесполезными выражениями, направленными на то, чтобы замолчать несколько предупреждений.

  • Вам не нужно явно определять функцию поддержки, чтобы сделать это.

Конечно, это не относится к статическим переменным, объявленным в теле функции, но вы можете сделать нечто подобное при возврате из функции (просто пример):

int f() {
    static int i = 0;
    static int j = 0;
    return void(i), void(j), 42;
}

int main () {}

Больше руды, меньше тех же преимуществ.

Я хотел бы предложить альтернативу для тех, кто компилирует с помощью ARM.

Вы можете использовать ключевое слово_attribute _ , чтобы назначить переменной. Это приведет к тому, что компилятор не будет генерировать никаких предупреждений, если на переменную не будет ссылки.

Вы можете присвоить атрибут «unused» параметру метода в объявлении метода. Просто поместите ключевое слово атрибута сразу после имени переменной вместе с «неиспользуемым» атрибутом. Я привел пример ниже.

Пример:

      void someFunc(int x __attribute__((unused)) );

На документацию можно ссылаться «неиспользуемый» атрибутздесь.

Другие вопросы по тегам