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;
}
Ответы
Ответ 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 () {}
Больше руд меньше тех же преимуществ.