Есть ли способ определить, действует ли #pragma неуправляемый в С++/CLI?

У меня есть проект, который включает в себя некоторые высокопроизводительные родные заголовки С++, которые сильно используют шаблоны. Для этого проекта мы также обертываем заголовки и добавляем некоторый код, чтобы показать функциональность С# и других языков .NET. Мы будем называть этот заголовок "layout.h", и мы будем считать его третьим заголовком, который я не могу изменить.

В смешанной сборке С++/CLI относительно легко сделать ошибку и # включить из места в коде, где #pragma неуправляемый (или #pramga управляется (push, off)). Когда это происходит, шаблоны генерируют IL, и я получаю дополнительные управляемые/неуправляемые переходы при запуске кода, а производительность идет вниз.

Мой вопрос заключается в том, есть ли способ выполнить проверку времени компиляции перед #include, чтобы компиляция завершилась неудачно, если я случайно #including из неправильного контекста.

// File1.cpp, compiled in a mixed mode C++/CLI assembly with /clr
    ASSERT_UNMANAGED()
    #include <layout.h>

Моя наивная 1-я попытка проверена #ifdef _MANAGED, но это всегда определяется, находится ли я в неуправляемом блоке кода #pragma или нет.

Ответ 1

Директивы прагмы должны быть вставлены непосредственно в файл include. Таким образом, везде, где вы включаете файл, объявляется неуправляемый раздел.

Извините, что вам нужно изменить свой файл include.

Ответ 2

Вы можете написать код ASSERT_MANAGED или ASSERT_UNMANAGED, который будет использовать конструкцию, доступную ТОЛЬКО при компиляции управляемых или неуправляемых. Объявление ref class - это пример, доступный только при использовании управляемого.

Это несколько грязное решение, но оно будет работать.

Ответ 3

Здесь возможное решение, использующее тот факт, что встроенные функции всегда компилируются как нативный (неуправляемый) код:

#include <intrin.h>

#define ASSERT_UNMANAGED() \
int TestFunc(void) { \
    __pragma(warning(push)) \
    __pragma(warning(error:4793)) \
    auto aumt = [] () { return _bextr_u64(65537, 0, 8); }; \
    __pragma(warning(pop)) \
    return int(aumt()); }

#pragma unmanaged   // Comment out this line and the assertion fails!
ASSERT_UNMANAGED()
#pragma managed

ОБНОВЛЕНИЕ: Конечно, если вам нужны предупреждения, а не ошибка компиляции, вы можете удалить 3 строки __pragma(warning()).