Подтвердить что ты не робот

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;
}
4b9b3361

Ответ 1

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

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

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

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

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. Поэтому, когда приложение заканчивается, деструктор вызывается и может деинициализировать.

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

Ответ 2

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

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

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

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

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

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

И еще для многих:

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

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

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

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

Ответ 3

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

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


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

Ответ 4

Как альтернатива, не удаляя 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
}

Ответ 5

Я думаю, что у вас есть проблема 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);
 }

Ответ 6

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

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 () {}

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