Переконайтесь, що час компіляції викликається саме в одному місці


15

Мені цікаво, чи можна за час компіляції забезпечити виклик методу саме в одному місці.

Зауважте, що це нормально, якщо функція викликається декілька разів (наприклад, у циклі) - але вона не повинна викликатися у двох окремих циклах.

Це можна розбити на дві частини, мене також цікавлять рішення, які охоплюють будь-яку частину:
(a) забезпечення того, що метод викликається принаймні в одному місці
(b) забезпечення методу виклику щонайменше в одному місці

Я маю повний контроль над структурою коду, і різні ідіоми, які досягають тієї самої ідеї, вітаються.

// class.h

class MyClass {
  public:
    void my_method();
}

Далі не слід збирати (ніколи не називатись)

#include "class.h"

int main() {
  MyClass my_class;
}

Далі не слід компілювати (викликається у більш ніж одному місці)

#include "class.h"

int main() {
  MyClass my_class;
  my_class.my_method();
  while(true) {
    my_class.my_method();
  }
}

Складається наступне (називається саме в одному місці):

#include "class.h"

int main() {
  MyClass my_class;
  while(true) {
    my_class.my_method();
  }
}

2
Не робіть це методом. Покладіть код в рядку в одне місце.
користувач207421

2
Я думаю, ви також могли це зробити з лямбда (це може бути порожня лямбда), оскільки тип закриття є унікальним для кожної лямбда. Знову ж таки, це буде помилка виконання, але це не те, про що ви просили. Якщо ви надасте детальну інформацію про проблему, яку ви намагаєтеся вирішити, ми можемо знайти спосіб вирішити цю проблему.
Індіана Кернік

2
Ви можете використовувати нестандартний __COUNTER__макрос для цього. Щось подібне static_assert(__COUNTER__ == 0); my_class.my_method();. Однак лічильник скидається в кожну одиницю перекладу, щоб ви могли лише перевірити, чи функція викликається один раз на одиницю перекладу.
Індіана Кернік

4
Чому ти хочеш це робити? Частина точки функції полягає в тому, що її можна викликати з декількох місць.
Чіпстер

4
Ви повинні пояснити, чому ви хочете це зробити. Можливо, рішення, про яке ви просите, не найкраще для досягнення ваших реальних цілей.
десять четвертого

Відповіді:


6

Низький технічний підхід:

Оскільки ви маєте контроль над структурою коду (яка включає систему збирання, я припускаю), ось низькотехнологічне рішення:

  • зробити назву функції достатньо унікальною
  • grep для імені функції у вашому коді. Ви очікуєте цього двічі (якщо вважати, що декларація та визначення є кольоровими):
    • Одного разу в заголовку
    • Одного разу на сайті одного дзвінка

Як варіант:

Якщо ви дійсно дуже хочете вирішити це за допомогою C ++, то можете спробувати

  • Використовуйте лічильник часу компіляції, щоб визначити кількість використання в одиницях компіляції
  • Переконайтеся, що функція порушить ODR, якщо заголовок включений у кілька одиниць компіляції.

Однак лічильники часу компіляції - це чорна магія (каже, що мені дуже подобається TMP), і примушування порушень ODR для цієї мети здається схожим на вуду (принаймні, вам знадобиться тестовий випадок, який не вдається зв’язати).

Але серйозно:

Не робіть цього. Що б ви не робили, це може перешкоджати майже без зусиль функцією обгортки:

auto call_my_method(MyClass& o)
{
   return o.my_method();
}

MyClass::my_method()називається тільки в обгортці. Всі інші просто називають обгортку, яку, мабуть, навіть накреслив компілятор.

Як запропонували інші: Це може бути набагато кориснішим, якщо ви поясните, що ви намагаєтеся зробити.


1

Ось приблизна ідея, яка може спрацювати (занадто довго для коментарів, але неповна для гарної відповіді ТА).

Ви можете досягти цього за допомогою підрахунку / перевірки екземплярів шаблону.
Шаблони створюються миттєво лише під час використання .

Аналогічно, тіло методу / функції функцій шаблону не розбираються, не компілюються і не пов'язані (крім забезпечення дійсного синтаксису), якщо вони ніколи не викликаються. Це означає, що будь-які моменти всередині їхніх органів не робляться).

Можливо, ви зможете створити шаблон, який підтримує деякий глобальний підрахунок інстанцій і статичне твердження на цьому (або якийсь інший механізм TMP для перевірки минулих даних).


"Глобальний" підрахунок інстанцій буде локальним для поточної одиниці компіляції.
атосимвол

1

Існує часткове вирішення цього питання за допомогою вбудованої збірки препроцесора C та GNU:

Файл заголовка a.h:

struct A {
    // Do not call this method directly, use the macro below to call it
    int _method_vUcaJB5NKSD3upQ(int i, int j);
};

// Use inline assembly to ensure that this macro is used at most once
#define method_vUcaJB5NKSD3upQ(args...) \
    _method_vUcaJB5NKSD3upQ(args); \
    asm (".global once_vUcaJB5NKSD3upQ; once_vUcaJB5NKSD3upQ:");

Файл реалізації a.cc:

#include <iostream>
#include "a.h"

int A::_method_vUcaJB5NKSD3upQ(int i, int j) { return i+j+5; }

// Ensure that the macro is used at least once
extern "C" const char once_vUcaJB5NKSD3upQ;
static const char get_vUcaJB5NKSD3upQ = once_vUcaJB5NKSD3upQ;

int main() {
    A a;
    for(int i=0; i<7; i++) {
        // Use a separate statement to call the method
        // (terminated by a semicolon, it cannot be a sub-expression)
        auto x = a.method_vUcaJB5NKSD3upQ(2, 3);
        std::cout << x << std::endl;
    }
    return 0;
}

Це рішення є частковим у тому сенсі, що не заважає програмі викликати метод, що починається з підкреслення безпосередньо, без використання макросу обгортки.


0

Використовуйте лічильник constexpr. В іншому питанні є реалізація


1
Здається, цей метод неправильно сформований.
Чіпстер

Питання open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#2118, на яке посилається у відповіді на це запитання, стверджує, що це помилка стандарту і його слід неправильно формувати.
SD57

Так це не погано сформовано, принаймні ще ні?
Чіпстер

Якщо він ще не сформований, його слід використовувати якомога швидше якомога більше людей, щоб вони мали підтримати цю справу використання!
користувач1685095
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.