Skip to content

Conversation

@oldnewthing
Copy link
Member

A common error is forgetting to provide the name of the derived class as the first implements<> template parameter. This results in a strange 'implements_type' is not a member of any direct or indirect base class of 'MyClass' error. Detect this case with a static_assert with a more help error message.

Note that we have to put the static_assert inside the implementation of GetRuntimeClassName rather than putting it in the class definition of implements. That's because implements is sometimes used with an incomplete type, and we cannot use is_base_of with incomplete types. Wait until GetRuntimeClassName is generated, at which point the class is complete.

A common error is forgetting to provide the name of the derived
class as the first `implements<>` template parameter. This results
in a strange `implements_type is not defined` error. Detect this
case with a `static_assert` with a more help error message.

Note that we have to put the `static_assert` inside the implementation
of `GetRuntimeClassName` rather than putting it in the class definition
of `implements`. That's because `implements` is sometimes used with
an incomplete type, and we cannot use `is_base_of` with incomplete types.
Wait until `GetRuntimeClassName` is generated, at which point the class
is complete.
@kennykerr
Copy link
Collaborator

Same here: I kicked off a build - there were vpack issues, but otherwise the build was successful.

What's the error look like?

@kennykerr kennykerr merged commit 7ddfc79 into master Jun 14, 2021
@kennykerr kennykerr deleted the implements_error branch June 14, 2021 16:16
@oldnewthing
Copy link
Member Author

struct Foo : winrt::implements<winrt::Windows::Foundation::IStringable, winrt::Windows::Foundation::IClosable>
{  //<< Line 25
    void Close() { }
    winrt::hstring ToString() { return L""; }
};

void test()
{
    auto foo = winrt::make<Foo>();
}

Before

Severity Code Description Project File Line
Error C2794 'implements_type': is not a member of any direct or indirect base class of 'winrt::Windows::Foundation::IStringable' test base.h 6613
base.h(6613,69): error C2794: 'implements_type': is not a member of any direct or indirect base class of 'winrt::Windows::Foundation::IStringable'
base.h(6633): message : see reference to alias template instantiation 'winrt::impl::implemented_interfaces<winrt::Windows::Foundation::IStringable>' being compiled
base.h(7707): message : see reference to class template instantiation 'winrt::impl::implements_default_interface<D,void>' being compiled
1>        with
1>        [
1>            D=winrt::Windows::Foundation::IStringable
1>        ]
base.h(7707): message : while compiling class template member function 'winrt::hstring winrt::implements<winrt::Windows::Foundation::IStringable,winrt::Windows::Foundation::IClosable>::GetRuntimeClassName(void) const'
test.cpp(25): message : see reference to class template instantiation 'winrt::implements<winrt::Windows::Foundation::IStringable,winrt::Windows::Foundation::IClosable>' being compiled

base.h(6613) is

    template <typename T>
    using implemented_interfaces = filter<is_interface, typename T::implements_type>;

which doesn't really give the developer much to work from.

After

Severity Code Description Project File Line
Error C2338 Class must derive from implements<> or ClassT<> where the first template parameter is the derived class name, e.g. struct D : implements<D, ...> test base.h 7708
base.h(7708,32): error C2338: Class must derive from implements<> or ClassT<> where the first template parameter is the derived class name, e.g. struct D : implements<D, ...>
base.h(7707): message : while compiling class template member function 'winrt::hstring winrt::implements<winrt::Windows::Foundation::IStringable,winrt::Windows::Foundation::IClosable>::GetRuntimeClassName(void) const'
test.cpp(25): message : see reference to class template instantiation 'winrt::implements<winrt::Windows::Foundation::IStringable,winrt::Windows::Foundation::IClosable>' being compiled

Line 7708 is

static_assert(std::is_base_of_v<implements_type, D>, "Class must derive from implements<> or ClassT<> where the first template parameter is the derived class name, e.g. struct D : implements < D, ...>");

This is then followed by the "Before" error.

Note

We still have an inscrutable error if you write

struct Foo : winrt::implements<winrt::Windows::Foundation::IClosable>
{ ... };

In that case you get

Severity Code Description Project File Line
Error C2039 'first_interface': is not a member of 'winrt::impl::interface_list<>' test base.h 6633

at

        using type = typename default_interface<typename implemented_interfaces<T>::first_interface>::type;

Still working on that one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants