visual-c++windows-runtimec++-winrtwinrt-component

How can I use the same namespace names in cpp-winrt idl file and a normal/standard cpp class?


The scenario is new and I believe it might be a bug in cpp-winrt module or the vc compiler.

The Problem
1. Create a "windows runtime component" using the cpp-winrt template for universal windows.
2. Note the namespace name defined in the idl file. By default the idl file is named as class.idl.
3. Add a "new standard cpp class" to the project using the class wizard.
4. Put the new class under the same namespace name as defined in the idl file.
5. Build the project.
a. The build should succeed.
6. Use the standard cpp class in the runtime implementation class.
7. Now try to build the project again.
a. The build will fail this time.

The Reason
1. cppwinrt.exe generates source files from the idl file.
2. The runtime implementation class namespace is prefixed by "winrt".
3. The standard cpp class is not prefixed by the namespace "winrt".
4. The vc compiler expects the standard cpp class namespace to start from "winrt"
5. Otherwise the name resolution fails even if you try to use the fully qualified namespace name.

Example runtime idl file


namespace NMLevel1.NMLevel2
{
    [default_interface]
    runtimeclass Class
    {
        Class();
        void RuntimeMethod1();
        Int32 RuntimeMethod2(Int32 arg1);
        String RuntimeMethod3(String arg1);
        Int32 MyProperty;
    }
}

Example standard cpp file

#pragma once
#include <string>
using namespace std;

namespace NMLevel1::NMLevel2
{
    class StdCPPClass
    {
    public:
        StdCPPClass();
        virtual ~StdCPPClass();

        void method1();
        int method2(int arg1);
        wstring method3(wstring arg1);
    };
}

Example runtime class implementation

#include "pch.h"
#include "Class.h"
#include "NMLevel1.NMLevel2.Class.g.cpp"
#include "StdCPPClass.h"

using namespace winrt;
using namespace Windows::Foundation;

namespace winrt::NMLevel1::NMLevel2::implementation
{
    void Class::RuntimeMethod1()
    {
        NMLevel1::NMLevel2::StdCPPClass stdcls;

        Uri uri(L"http://aka.ms/cppwinrt");
        //printf("Hello, %ls!\n", uri.AbsoluteUri().c_str());
        printf("RuntimeMethod1(): Hello, %ls!\n", stdcls.method3(uri.AbsoluteUri().c_str()).c_str());
    }
}

NMLevel1::NMLevel2::StdCPPClass stdcls; is not allowed without prefixing the namespace with winrt.

Is this a bug or a design limitation that cannot be overcome? or How can I use the same namespace 'NMLevel1::NMLevel2' in idl and cpp files?


Solution

  • Name lookup in C++ is fairly involved, especially when namespaces get essentially merged through using declarations. To help the compiler identify the name you want, you'll have to be explicit, and use a fully qualified name (as opposed to a qualified name, as in the sample).

    You'll have to change

    void Class::RuntimeMethod1()
    {
        NMLevel1::NMLevel2::StdCPPClass stdcls;
        // ...
    }
    

    to

    void Class::RuntimeMethod1()
    {
        ::NMLevel1::NMLevel2::StdCPPClass stdcls;
        // ...
    }
    

    Note the leading :: scope resolution, which limits lookup to the global scope (or namespaces introduced into the global namespace through a using declaration). You'll find additional information here: Qualified name lookup.