Можно ли использовать C++/CX и C++/WinRT в одном проекте?

Ранее на этой неделе Кенни Керр представил C++/WinRT на CppCon 20161. Это стандартная проекция C++ для среды выполнения Windows, основанная на Modern.

Насколько я понимаю, компилятор/препроцессор/код C++/CX генератор не затрагивает стандартный код C++, а поскольку C++/WinRT является стандартной библиотекой C++, моя наивная интерпретация состоит в том, что и C++/CX, и C++/WinRT можно использовать в одном проекте.

Вопросы:

  • Перво-наперво: верна ли моя наивная интерпретация?
  • Если да, то можно ли использовать C++/CX и C++/WinRT в одной и той же единице компиляции?
  • С какой степенью детализации можно смешивать C++/CX и C++/WinRT, если они не могут находиться в одной и той же единице компиляции?
  • Может ли C++/WinRT использовать типы, реализованные с помощью C++/CX, в одном проекте? (Я ожидаю, что это будет сложно, поскольку компилятору C++/WinRT необходимо генерировать заголовки из метаданных .winmd, поэтому существует зависимость от (до)вывода компилятора.)

Если это важно, ответы на эти вопросы позволяют мне уже сейчас принимать решения о том, как перенести мои проекты C++/CX в будущее.


1 Стандартный C++ для среда выполнения Windows (на YouTube).


person IInspectable    schedule 25.09.2016    source источник
comment
Хмя, надо посмотреть, над чем он работал последний год, он не обновлял свой депозитарий на гитхабе. Если у вас никогда раньше не было веских причин для погружения в WRL, то маловероятно, что C++/WinRT будет крутить винты. Это действительно то, что есть, по крайней мере, вариант moderncpp, еще одна оболочка, подобная WRL, но обновленная для C++1xyz. Код Керра и Макнеллиса вызывает у меня головную боль, вы можете увидеть, что он делает, но нелегко понять, чего он не делает.   -  person Hans Passant    schedule 25.09.2016
comment
@HansPassant: основной причиной для C++/WinRT (по сравнению с C++/CX) будет производительность. Время компиляции невелико, а сообщения об ошибках обычно представляют собой хорошие загадки. Тем не менее, мне нравится лаконичный (или слишком краткий, если хотите) синтаксис больше, чем явные вызовы WRL (хотя я могу изменить свое мнение, поскольку мне впервые приходится отлаживать реальную проблему). Я согласен, что труднее увидеть, что код делает (или не делает). Но это так же верно и для C#/.NET, и это никогда не мешало тому, чтобы сделать его предпочтительной целью для многих людей. В любом случае, личные предпочтения личные, я думаю;)   -  person IInspectable    schedule 26.09.2016
comment
Я не эксперт по C++, но... почему бы и нет? В проектах C++/CX может быть обычный код C++, а C++/WinRT — это просто обычный C++, верно?   -  person Filip Skakun    schedule 27.09.2016
comment
@FilipSkakun: Это был и мой первоначальный инстинкт. На уровне исходного кода обе языковые проекции могут легко сосуществовать. Тем не менее, здесь также задействованы инструменты. Компилятор C++/CX генерирует код из ref classes, а также метаданных .winmd, поэтому использование кода ref class из C++/WinRT в одной и той же единице компиляции может оказаться затруднительным. При компиляции кода требуется ввод .winmd, который является продуктом компиляции. Кроме того, я не знаю, создает ли компилятор C++/CX какой-либо код из импортированных данных .winmd, который (потенциально) конфликтует с C++/WinRT #includes.   -  person IInspectable    schedule 27.09.2016


Ответы (2)


Относительно вопроса «Может ли C++/WinRT использовать типы, реализованные с помощью C++/CX, в одном проекте?»

Ответ: и да, и нет. Если «ссылочный класс» определен в том же проекте, поскольку такой проект должен быть скомпилирован с включенным C++/CX, ваш код может просто использовать этот класс, как и любой ссылочный класс.

Однако, если вы хотите использовать «ссылочный класс» как проекцию C++/WinRT, ответ фактически будет отрицательным.

Чтобы получить определение спроецированного класса C++/WinRT, необходимо запустить компилятор cppwinrt.exe над метаданными для «ссылочного класса». Это потребует как-то получить метаданные. Вы можете настроить какой-то механизм для компиляции «ссылочного класса» один раз, получить winmd, обработать его с помощью mdmerge, чтобы привести его в каноническую форму, запустить cppwinrt.exe для метаданных, чтобы получить определение спроецированного класса, а затем включить сгенерированные заголовки.

Кроме того, вы можете написать IDL для описания «класса ссылок», скомпилировать его в метаданные с помощью MIDLRT, а затем запустить cppwinrt.exe. Ни то, ни другое не является практичным ИМО.

Наиболее разумная альтернатива — просто использовать класс ref как есть как тип C++/CX, поскольку определение находится в том же решении. Следующее наиболее практичное решение — поместить класс в отдельный проект, скомпилировать его, получив winmd, а затем создать заголовки из winmd. Этот подход также позволяет создавать отдельный проект, использующий «класс ссылки» (через проекцию), без использования кода C++/CX.

Чтобы быть полностью прозрачным, обратите внимание, что наш первоначальный выпуск (теперь доступен по адресу https://github.com/Microsoft/cppwinrt) не включает в себя сам компилятор cppwinrt.exe. Вместо этого он содержит файлы заголовков C++/WinRT, содержащие прогнозы для всех типов/API среды выполнения Windows, определенных в пакете SDK для юбилейного обновления Windows 10, включая API универсальной платформы и все API Extension SDK.

person Brent Rector    schedule 29.09.2016
comment
Это отличное резюме, спасибо за него. Это примерно так, как я понял. За исключением того, что я полностью упустил тот (теперь очевидный) факт, что вы можете просто использовать ref classes, используя языковые расширения C++/CX в стандартном коде C++ (например, C++/WinRT). И пока вы намекали на это: как скоро скоро? Такое ощущение, что я теряю сон из-за этого уже больше года. Отсутствие компилятора впереди немного разочаровывает, хотя я понимаю, что вам нужно сделать все правильно с первого раза. - person IInspectable; 29.09.2016
comment
Чтобы C++/WinRT использовал типы C++/CX, попробуйте применить gist.github.com/kennykerr/105f96d61f51b5773670844edec99d85 пока. :) - person Chawathe Vipul S; 10.05.2017

Короткий ответ: да, C++/CX и C++/WinRT можно использовать в одном проекте.

Компилятор C++/CX внедряет типы Winmd в корневое пространство имен. C++/WinRT упаковывает все в собственное корневое пространство имен winrt, чтобы обеспечить взаимодействие с C++/CX и избежать ошибок неоднозначности компилятора C++ с другими библиотеками. Итак, следующий код C++/CX:

using namespace Windows::Foundation;
using namespace Windows::Networking;

Uri ^ uri = ref new Uri(L"https://moderncpp.com/");
HostName ^ name = ref new HostName(L"moderncpp.com");

Можно переписать с помощью C++/WinRT следующим образом:

using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Networking;

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");

В качестве альтернативы, если вы компилируете с /ZW, вы можете переписать его следующим образом (чтобы избежать ошибки C2872: «Windows»: неоднозначный символ):

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Networking;

Uri uri(L"https://moderncpp.com/");
HostName name(L"moderncpp.com");

Другой способ объединения C++/CX и C++/WinRT в одном исходном файле — использовать корневое пространство имен для обоих, как показано ниже.

namespace cx
{
    using namespace Windows::Foundation;
    using namespace Windows::Networking;
}

namespace winrt
{
    using namespace Windows::Foundation;
    using namespace Windows::Networking;
}

void Sample()
{
    cx::Uri uri(L"https://moderncpp.com/");
    winrt::HostName name(L"moderncpp.com");
}

В конце концов, C++/WinRT — это просто стандартная библиотека C++, которую можно включить в любой применимый проект C++. Однако C++/CX и C++/WinRT по-разному обрабатывают метаданные. C++/CX потребляет и создает метаданные напрямую, тогда как C++/WinRT ограничивается стандартным C++ и поэтому требует автономного инструмента (cppwinrt.exe), чтобы помочь преодолеть этот разрыв.

person Kenny Kerr    schedule 27.09.2016
comment
Большое спасибо за ответ. Таким образом, на исходном уровне как C++/CX, так и C++/WinRT могут благополучно сосуществовать в одной и той же единице компиляции. Однако неоднородный инструментарий может потребовать разделения (когда потребители и производители живут в разных языковых проекциях). Однако мне не понятна одна деталь: может ли cppwinrt.exe извлекать метаданные .winmd из исходного или объектного кода C++/WinRT? Или существуют дополнительные требования (например, файлы MIDL) для публикации реализаций C++/WinRT для использования другими языковыми проекциями? - person IInspectable; 29.09.2016
comment
Они могут сосуществовать, но следует отметить, что поведение некоторых специфических заголовков системы/утилиты меняется при сборке с /ZW, чем без него, а некоторые заголовки требуют этого. Это также может привести к дополнительным предупреждениям компилятора, которые не появляются, если вы используете C++/WinRT без /ZW. - person Chuck Walbourn; 29.11.2017
comment
Казалось бы, чтобы ответить на вопросы ОП, /ZW не может одновременно присутствовать и отсутствовать в одной и той же единице компиляции. Следовательно, для стандартных конструкций C++ наименьшая степень детализации для C++/CX и C++/WinRT для сосуществования в одном проекте — это разные единицы компиляции в одной и той же единице компоновки (например, DLL; EXE). Но для конструкций .NET единственный способ сосуществования — это представление этих конструкций .NET в C++/CX (и C#) и C++/WinRT — •• ни в коем случае •• в обход за кулисами через стандартный домен C++. - person Andreas ZUERCHER; 12.02.2018