Как заставить общие компиляторы C ++ распечатать пространство имен, в котором находится определенная строка? - PullRequest
3 голосов
/ 06 мая 2019

Я пытаюсь выяснить, где в куче кода мне не хватает закрывающей скобки для пространства имен (то есть, получая:

At end of source: error: expected a "}"

ошибка). Возможно, есть более разумные способы сделать это, но - я хочу попробовать и проверить в разных точках моего кода, каково текущее пространство имен. Мне не нужен макрос; и мне не нужна строка; и мне не нужно то, что будет существовать во время выполнения. Я просто хочу, чтобы компилятор как-то печатал пространство имен. Это нормально для меня, если он находится в #error, #warning или какой-либо конструкции, которая, если не скомпилируется, выдает ошибку с пространством имен в нем.

Пример, который я хочу обобщить:

namespace ns1 { }
namespace ns2 {
namespace ns3 {

// MAGIC GOES HERE

}

этот исходный файл где-то отсутствует }. Но - я забыл закрыть ns1? Или может быть ns2? Я не помню - они находятся далеко от линии, в которой я заинтересован. Поэтому я хочу вставить что-то волшебное, которое скажет мне, в каком пространстве имен я сейчас нахожусь. Ну, для этого примера я могу написать:

namespace ns1 { }
namespace ns2 {
namespace ns3 {

void ns_detector() { return 0; }

}

и с GCC 6.3, получите ошибку:

b.cpp: In function ‘void ns2::ns3::ns_detector()’:
b.cpp:5:29: error: return-statement with a value, in function returning 'void' [-fpermissive]
 void ns_detector() { return 0; }
                             ^
b.cpp: At global scope:
b.cpp:7:1: error: expected ‘}’ at end of input
 }
 ^

Первая строка этой ошибки говорит мне, что мне нужно знать: это ns2, который не был закрыт. Но - это не так надежно. Для более длинных, более сложных фрагментов кода, которые я компилирую с помощью nvcc, используя функцию «ns Detector», я получаю только что-то вроде:

/path/to/file.cu(135): error: return value type does not match the function type

At end of source: error: expected a "}"

Итак, мне нужно что-то более крепкое.

Примечания:

  • Решение должно быть фиксированным фрагментом кода, который я вставляю в свой собственный код, где я хочу проверить, что такое пространство имен и, возможно, дополнительные флаги компилятора для использования.
  • Решение должно работать для максимально возможного числа: gcc, clang, nvcc, msvc, icc. Мне особенно важны nvcc (компилятор CUDA) и gcc.
  • Я бы предпочел наименьшее возможное количество "шума", кроме пространства имен и некоторого "текста маркера", который я буду искать в выходных данных.
  • Несколько связанный вопрос: Как получить строку для текущего пространства имен в макросе

Ответы [ 2 ]

1 голос
/ 06 мая 2019

A (возможное) улучшение хорошего и простого решения @ Acorn, которое можно использовать много раз для обнаружения в нескольких местах в одном файле:

#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)

#define DETECT_NAMESPACE \
struct UNIQUE_IDENTIFIER(namespace_detector_on_line_) { \
    void f() { look_at_the_class_name_above = 0; } \
};

Теперь вы должны иметь возможность писать DETECT_NAMESPACE на многих разных строках. Кроме того, определения макросов могут быть помещены в отдельный файл.

Для кода в примере это даст:

b.cpp: In member function ‘void ns2::ns3::namespace_detector_on_line_13::f()’:
b.cpp:5:93: error: ‘look_at_the_class_name_above’ was not declared in this scope
 #define DETECT_NAMESPACE struct UNIQUE_IDENTIFIER(namespace_detector_on_line_) { void f() { look_at_the_class_name_above! = 0; } };
                                                                                             ^
b.cpp:13:1: note: in expansion of macro ‘DETECT_NAMESPACE’
 DETECT_NAMESPACE
 ^~~~~~~~~~~~~~~~
b.cpp: At global scope:
b.cpp:15:1: error: expected ‘}’ at end of input
 }
1 голос
/ 06 мая 2019

Это будет зависеть от компиляторов и их версий. Тот, который в настоящее время работает для всех gcc, clang, icc и msvc (сообщите нам, работает ли он для nvcc!), Обращается к отсутствующему элементу данных:

struct A { A() { this->a; } };

Все компиляторы сообщат об ошибке с указанным именем, например ::

error: no member named 'a' in 'foo::bar::A'

Таким образом, вы можете легко найти для ::A' или ::A" и извлечь его (все эти 4 основных компилятора помещают имя в кавычки; в противном случае просто используйте уникальный идентификатор, который вы не найдете больше нигде и т. Д.).

...