Кто-нибудь когда-либо использовал макрос __COUNTER__ pre-processor?

Символ __COUNTER__ предоставлен VC ++ и GCC, и каждый раз, когда он используется, он получает все возрастающее неотрицательное целочисленное значение.

Мне интересно узнать, кто-нибудь когда-либо использовал его, и стоит ли это стандартизировать?

Он используется в библиотеке покрытия кода xCover , чтобы пометить строки, выполнение которых проходит, чтобы найти те, которые не покрыты.

__COUNTER__ полезен везде, где вам нужно уникальное имя. Я использовал его широко для замков и стеков стиля RAII. Рассматривать:

 struct TLock { void Lock(); void Unlock(); } g_Lock1, g_Lock2; struct TLockUse { TLockUse( TLock &lock ):m_Lock(lock){ m_Lock.Lock(); } ~TLockUse(){ m_Lock.Unlock(); } TLock &m_Lock; }; void DoSomething() { TLockUse lock_use1( g_Lock1 ); TLockUse lock_use2( g_Lock2 ); // ... } 

Достаточно назвать использование блокировок и даже стать источником ошибок, если они не все объявлены в верхней части блока. Откуда вы знаете, находитесь ли вы в lock_use4 или lock_use11 ? Это также ненужное загрязнение пространства имен – мне никогда не нужно ссылаться на объекты использования блокировки по имени. Поэтому я использую __COUNTER__ :

 #define CONCAT_IMPL( x, y ) x##y #define MACRO_CONCAT( x, y ) CONCAT_IMPL( x, y ) #define USE_LOCK( lock ) TLockUse MACRO_CONCAT( LockUse, __COUNTER__ )( lock ) void DoSomething2() { USE_LOCK( g_Lock1 ); USE_LOCK( g_Lock2 ); // ... } 

Но не зацикливайтесь на том, что я вызывал блокировки объектов – любая функция (ы), которая должна быть вызвана в соответствующие пары, соответствует этому шаблону. Возможно, у вас может быть несколько применений в одной и той же «блокировке» в данном блоке.

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

  • Способы выражения ASSERT во время сборки в C

если вы хотите детали gory.

Я никогда не использовал его ни для чего, кроме макроса DEBUG. Удобно говорить

 #define WAYPOINT \ do { if(dbg) printf("At marker: %d\n", __COUNTER__); } while(0); 

Мне интересно узнать, кто-нибудь когда-либо использовал его,

Да, но, как вы можете видеть из многих примеров в этом Q & A, стандартная стандартная __LINE__ также будет достаточной в большинстве случаев.

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

и стоит ли это стандартизировать?

__COUNTER__ , в отличие от __LINE__ , очень опасен, потому что он зависит от того, какие заголовочные файлы включены и какой порядок. Если два файла .cpp (единицы перевода) include заголовочный файл, который использует __COUNTER__ , но заголовочный файл получает разные последовательности отсчетов в разных экземплярах, они могут использовать разные определения одной и той же вещи и нарушать правило одного определения.

Нарушения правил с одним определением очень сложно уловить и потенциально создавать ошибки и риски безопасности. Несколько вариантов использования __COUNTER__ самом деле не перевешивают недостаток и отсутствие масштабируемости.

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

Если я правильно понимаю функциональность, мне хотелось, чтобы у меня была такая функциональность, когда я работал в Perl, добавив функцию регистрации событий в существующий графический интерфейс. Я хотел убедиться, что необходимое ручное тестирование (вздох) дало нам полный охват, поэтому я зарегистрировал каждую тестовую точку в файле, а регистрация значения __counter__ позволила легко увидеть, чего не хватает в покрытии. Как бы то ни было, я подал закодированный эквивалент.

Он используется Boost.Asio для реализации стекированных сопрограмм.

См. Этот заголовочный файл и примеры .

Итоговые сопрограммы выглядят следующим образом:

 struct task : coroutine { ... void operator()() { reenter (this) { while (... not finished ...) { ... do something ... yield; ... do some more ... yield; } } } ... }; 

Я использовал его для создания уникальных типов в этой статье: http://www.codeproject.com/Articles/42021/Sealing-Classes-in-C

Я намерен использовать __COUNTER__ чтобы дать каждому файлу в нашей базе кода уникальный идентификатор, чтобы этот уникальный код можно было использовать при регистрации ASSERT во встроенной системе.

Этот метод намного эффективнее, чем использование строк для хранения имен файлов (с использованием __FILE__ ), особенно во встроенной системе с маленьким ROM. Я думал об этой идее, пока читал эту статью – Assert Yourself на Embedded.com. Жаль, что он работает только с компиляторами на основе GCC.

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

__COUNTER__ гарантированно будет уникальным, в отличие от __LINE__ . Некоторые компиляторы позволяют __LINE__ . #include файлы также будут сброшены __LINE__ .

Использование выполняется в макросе REGISTER_KERNEL_BUILDER TensorFlow . Каждый TensorFlow Op может иметь одно или несколько ядер в качестве своих реализаций. Эти ядра регистрируются у регистратора. Регистрация ядра выполняется путем определения глобальной переменной – конструктор переменной может выполнить регистрацию. Здесь авторы используют __COUNTER__ чтобы дать каждой глобальной переменной уникальное имя.

 #define REGISTER_KERNEL_BUILDER(kernel_builder, ...) \ REGISTER_KERNEL_BUILDER_UNIQ_HELPER(__COUNTER__, kernel_builder, __VA_ARGS__) #define REGISTER_KERNEL_BUILDER_UNIQ_HELPER(ctr, kernel_builder, ...) \ REGISTER_KERNEL_BUILDER_UNIQ(ctr, kernel_builder, __VA_ARGS__) #define REGISTER_KERNEL_BUILDER_UNIQ(ctr, kernel_builder, ...) \ static ::tensorflow::kernel_factory::OpKernelRegistrar \ registrar__body__##ctr##__object( \ SHOULD_REGISTER_OP_KERNEL(#__VA_ARGS__) \ ? ::tensorflow::register_kernel::kernel_builder.Build() \ : nullptr, \ #__VA_ARGS__, [](::tensorflow::OpKernelConstruction* context) \ -> ::tensorflow::OpKernel* { \ return new __VA_ARGS__(context); \ }); 

Он используется в метрической системе ClickHouse.

 namespace CurrentMetrics { #define M(NAME) extern const Metric NAME = __COUNTER__; APPLY_FOR_METRICS(M) #undef M constexpr Metric END = __COUNTER__; std::atomic values[END] {}; /// Global variable, initialized by zeros. const char * getDescription(Metric event) { static const char * descriptions[] = { #define M(NAME) #NAME, APPLY_FOR_METRICS(M) #undef M }; return descriptions[event]; } Metric end() { return END; } } 
  • Глобальная переменная в нескольких файлах
  • статический член constexpr того же типа, что и class
  • Как выполнить итерацию свойств анонимного объекта в C #?
  • Гиперссылки html с asp.net mvc
  • Как указать указатель на перегруженную функцию?
  • Преобразование строки в DateTime
  • Что это за выражение «смайлик с бородой»: «"?
  • Чтение dll.config (не app.config!) Из модуля плагина
  • Разделить строку на строковый массив одиночных символов
  • Fluent NHibernate, работающий с интерфейсами
  • Как получить список коллекции значений из app.config в WPF?
  • Давайте будем гением компьютера.