Войти
ПрограммированиеФорумОбщее

[C++] Проверить наличие глобальной переменной

Страницы: 1 2 Следующая »
#0
(Правка: 20:20) 20:16, 13 сен 2022

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

Я попытался набросать такой детектор:

#define META_CHECK_IF_GLOBALLY_DECLARED_VAR(id) \
  namespace z_D {struct id##_DeclaredType {}; int id(id##_DeclaredType);} \
  template<typename T> concept z_D_##id##Declared = requires {id(T());}; \
  namespace MetaGloballyDeclaredVar {\
    namespace Exists {constexpr bool id = !z_D_##id##Declared<z_D::id##_DeclaredType>;} \
    namespace GetPtr {template<typename T> T* id() {return &::id;};} \
  }

Пример использования:

int declaredVar = 5;
META_CHECK_IF_GLOBALLY_DECLARED_VAR(declaredVar)
META_CHECK_IF_GLOBALLY_DECLARED_VAR(notDeclaredVar)
static_assert(MetaGloballyDeclaredVar::Exists::declaredVar);
static_assert(!MetaGloballyDeclaredVar::Exists::notDeclaredVar);

#include "third_party_file.h"

META_CHECK_IF_GLOBALLY_DECLARED_VAR(third_party_var)

// Должна вернуть third_party_var, если она объявлена в third_party_file.h.
// Иначе должна вернуть 0.
int getValOrZero()
{
  int* ptr = MetaGloballyDeclaredVar::GetPtr::third_party_var<int>();
  return ptr? *ptr: 0;
}

Exists уже отрабатывает как надо. А GetPtr надо реализовать, чтобы не было ошибки компиляции, когда переменная не определена. Возможно ли это реализовать?
Можно использовать C++20 фичи, но только те, которые можно заставить работать на GCC 8.

#1
20:37, 13 сен 2022

А нельзя как-то проще-тупее? Ну, например, инклудить файл в особом пространстве имен, в глобальном пространстве объявлять одноименную переменную, и во вложенном пространстве объявлять функцию-геттер, которая, если объявлено, будет возвращать объявленную, иначе - искать в глобальном и находить там условный нулл. Не подойдет?

#2
21:08, 13 сен 2022

Went
Не получится, у этих .h-файлов есть ещё .c-файлы с реализацией, а она в этот неймспейс не попадёт.

#3
21:31, 13 сен 2022

Went
> нельзя как-то проще-тупее?

#define DECLARED_VAR 5

...

#ifdef DECLARED_VAR
#endif
#4
21:47, 13 сен 2022

#!
Если бы в third_party_file.h были такие дефайны, этой темы бы не было. Я не могу повлиять на содержимое этих файлов. Править руками не вариант - их постоянно меняют.

#5
23:28, 13 сен 2022

grep пробовал?

#6
23:41, 13 сен 2022

gammaker
> requires {id(T());};
А с какого перепугу он тут для случая отсутствия декларации подставит символ из другого пространства имён (z_D)? Выглядит как ошибка компилятора. Или концепты игнорируют пространства имён?

#7
23:45, 13 сен 2022

Так не работает?

if constexpr (Exists) {
return &::id;
} else {
return nullptr;
}
#8
2:06, 14 сен 2022

А почему нельзя просто запустить скрипт, и по результату испольнения запускать необходимый макрос?
Но сама задача странная, что кто-то постоянно добавляет и удаляет глобальные переменные из подключаемых хедеров?

#9
9:15, 14 сен 2022

pahaa
> А с какого перепугу он тут для случая отсутствия декларации подставит символ из
> другого пространства имён (z_D)?
Это argument dependent lookup, довольно малоизвестная фича C++. Можно неявно вызвать функцию из другого пространства имён, если тип её аргумента определён в том же пространстве имён, что и она.
Этот трюк работает со всеми тремя компиляторами, я уже проверил.

pahaa
> Так не работает?
Нет, ошибка компиляции. Даже для ветки, которая не выполняется, компилятор проверяет синтаксис и что все идентификаторы объявлены.

inc_ani
> почему нельзя просто запустить скрипт, и по результату испольнения запускать
> необходимый макрос?
Там и так уже замудрёный скрипт сборки CMake. Не хочется усложнять его ещё больше. Но возможно придётся...

inc_ani
> Но сама задача странная, что кто-то постоянно добавляет и удаляет глобальные
> переменные из подключаемых хедеров?
Коллеги пользуются гуишным кодогенератором, который невозможно сделать частью скрипта, и генерируют код для десятка разных конфигураций сборки. Этот код попадает в мой репозиторий. Какие-то из конфигураций долго не обновляются, они сгенерированы старым кодогенератором, и там не хватает некоторых переменных. А мне нужно интегрировать приложение со сгенерированным кодом, чтобы оно работало со всеми конфигурациями.

#10
11:39, 14 сен 2022

> Этот код попадает в мой репозиторий.
Напиши свой локальный скрипт, который будет частью пайплайна сборки и будет генерировать промежуточный h, который будет адаптором для тебя и для них. Тоесть генератор кода их должен тебе обеспечить безопасный адаптер. А его нет.

#11
11:55, 14 сен 2022

gammaker
> компилятор проверяет синтаксис и что все идентификаторы объявлены
Тогда можно нагородить через SFINAE. Там такой проблемы не должно быть. Сходу без компилятора под рукой пример не могу придумать, но выглядит так, что std::enable_if должно помочь.

#12
14:06, 14 сен 2022

pahaa
> Сходу без компилятора под рукой пример не могу придумать, но выглядит так, что
> std::enable_if должно помочь.
Как и концепты, оно работает только с шаблонными классами и тем, что в них содержится. А это глобальный идентификатор.

lookid
> Напиши свой локальный скрипт, который будет частью пайплайна сборки
Не люблю эти скрипты, в них и так уже сложно ориентироваться и поддерживать их. Я всё же надеялся, что кто-то здесь предложит какой-то способ сделать это средствами плюсовой магии. Раньше gamedev в подобных случаях выручал. Но если никак, то видимо придётся со скриптами химичить...

#13
18:48, 19 сен 2022

Может быть, получится так:

int default_x = 42;

int *proxy_x = &default_x;

#define x x; int *cludge_x = (proxy_x = &x)

#include "..."
//extern int x;

#undef x

printf("%i\n", *proxy_x);
#14
12:25, 20 сен 2022

TelVolt
> Может быть, получится так:
Может быть с обычными переменными и прокатит, но с массивами нет.

Страницы: 1 2 Следующая »
ПрограммированиеФорумОбщее