Распечатать идентификатор класса, если он доступен - PullRequest
3 голосов
/ 13 марта 2020

Цель состоит в том, чтобы создать (макрос?), Который будет печатать уникальный идентификатор для экземпляра класса (например, указатель this), когда он помещен в функцию класса, и ничего (или что-то еще), когда используется в «нормальной» функции. Желательно без добавления чего-либо в класс, но если это единственный способ сделать это, я возьму это.

Вот моя попытка, однако это совсем не нравится использование this ( замена его на (void)1 делает его работоспособным, но мне нужен уникальный идентификатор для экземпляра класса. На g cc такие ошибки выглядят как: error: invalid use of ‘this’ in non-member function, а msv c имеет аналогичные ошибки: error C2355: 'this': can only be referenced inside non-static member functions or non-static data member initializers

нерабочий код:

#include <iostream>

class _detect_class_ {};
typedef int _class_sentinel_;

#define THIS_PTR std::is_same<_detect_class_, _class_sentinel_>::value ? (void*)this : nullptr
#define TRACK_THIS_OBJECT typedef _detect_class_ _class_sentinel_;

struct thisptr
{
    void* Ptr;
    thisptr(void* ptr): Ptr(ptr){;}
};

std::ostream& operator<<(std::ostream& strm, const thisptr& p)
{
    if (p.Ptr)
        strm << "Object:" << p.Ptr;
    else
        strm << "No object";
    return strm;
}

#define PRINT_ME    std::cout << thisptr(THIS_PTR) << std::endl;

struct TestStruct
{
    void Function1()
    {
        PRINT_ME;
    }
    TRACK_THIS_OBJECT
};

int main()
{
    TestStruct o1, o2;
    PRINT_ME;       // No object
    o1.Function1(); // Object: (identifier1)
    o2.Function1(); // Object: (identifier2)
    return 0;
}



Ответы [ 3 ]

1 голос
/ 13 марта 2020

Я изменяю ваш код, чтобы добавить пустой элемент (C ++ 20), чтобы получить ожидаемый результат:

_detect_class_ m; // To avoid error in THIS_PTR.

#define TRACK_THIS_OBJECT using _class_sentinel_ = _detect_class_; \
                          [[no_unique_address]]_detect_class_ m;

#define THIS_PTR std::is_same<_detect_class_, _class_sentinel_>::value ? &m : nullptr

Демо

1 голос
/ 13 марта 2020

Может быть, это слишком просто для продвинутых C++ гуру

// this is in header pretty_print.h
#include <iostream>
inline void pretty_print() {}

#define PRINTABLE                                                              \
  void pretty_print() { std::cout << this << std::endl; }
#define PRINT_ME pretty_print()
// end of header

// #include "pretty_print.h"
void moo() { PRINT_ME; }

struct Foo {
  PRINTABLE

  void foo() { PRINT_ME; }
};

int main() {
  PRINT_ME;
  moo();
  Foo().foo();
}

1 голос
/ 13 марта 2020

Самым простым трюком было бы объявить фиктивный класс на верхнем уровне с экземпляром указателя с именем "this".

Ваш макрос всегда будет видеть "this" и может решить не печатать, потому что this == & dummy.

Недостатком является то, что "this" является зарезервированным словом, и, вероятно, предупреждения компилятора, ошибки и разработчики стандартов не будут вашим другом. Вам это может сойти с рук, потому что компиляторы пытаются поддерживать обратную поддержку, а неклассовые методы не / не нуждаются / не резервируют "this".

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

Самый дешевый символ для объявления будет перечислением, так как они являются просто константами, но тогда как вы будете различать guish между глобальным и классовым вариантами, когда существует много вариантов классов? Конечно, вы можете использовать имя typeid в качестве синонима для содержащего класса.

Это мои идеи о том, чего они стоят.

Следующая самая дешевая - это, вероятно, встроенная функция-член, возможно, также встроенная функция-член c и глобальная функция, которая может вернуть ваш уникальный идентификатор (их указатель this и, возможно, также объект typeid). .

Гораздо более простым решением являются разные именованные версии макроса журнала, который вы используете в разных контекстах. Компилятор «поможет» вам, когда вы используете неправильный.

...