Nicolas Grinschgl
Nicolas Grinschgl

Reputation: 41

CLI/C++ Interface class, Generic method calling template method

I am currently coding an interface wrapper class which builds a bridge between managed code and a c++ class. As this c++ class does export template methods i have some troubles calling them. I want to expose a generic method which then calls the corresponding template method.

In the example below, i want to expose AppendData, which calls _AppendData, which then calls the template method.

I am getting a compile error for the _AppendData call: Error 1 error C2664: 'void managedInterface::Channel::_AppendData(cli::array ^)' : cannot convert argument 1 from 'cli::array ^' to 'cli::array ^' d:\sources\something\SomeExports.h 421 1

What am i doing wrong?

generic <typename T> void AppendData ( array<T> ^aArray)
    {
        _AppendData(aArray);
    }

internal:
    void _AppendData(array<char>                ^aArray);
    void _AppendData(array<short>               ^aArray);
    void _AppendData(array<int>                 ^aArray);
    void _AppendData(array<long long>           ^aArray);
    void _AppendData(array<unsigned char>       ^aArray);
    void _AppendData(array<unsigned short>      ^aArray);
    void _AppendData(array<unsigned int>        ^aArray);
    void _AppendData(array<unsigned long long>  ^aArray);
    void _AppendData(array<float>               ^aArray);
    void _AppendData(array<double>              ^aArray);

    template <typename T> void __AppendData(array<T> ^aArray)
    {

    }

Upvotes: 2

Views: 1007

Answers (1)

Lucas Trzesniewski
Lucas Trzesniewski

Reputation: 51330

Your syntax does not work for a simple reason: generics are reified at runtime, while templates are instantiated at compile time. This means that overload resolution for _AppendData(aArray); must be performed at compile time, but the type of aArray won't be known until runtime. These two situations are incompatible.

I'm afraid there's no better solution than this:

generic <typename T> void AppendData(array<T>^ aArray)
{
    if (dynamic_cast<array<char>^>(aArray) != nullptr)
    {
        _AppendData(safe_cast<array<char>^>(aArray));
        return;
    }

    if (dynamic_cast<array<short>^>(aArray) != nullptr)
    {
        _AppendData(safe_cast<array<short>^>(aArray));
        return;
    }

    // Do the same for the other ones

    throw gcnew System::NotSupportedException(System::String::Format("Unsupported type: {0}", T::typeid));
}

Except this code won't compile because of a MSVC bug :/

error C2681: 'cli::array<T, 1> ^': invalid expression type for dynamic_cast

So we'll have to work around this:

template <class T> bool is_instance_of(System::Object^ obj)
{
    return dynamic_cast<T>(obj) != nullptr;
}

generic <typename T> void AppendData(array<T>^ aArray)
{
    if (is_instance_of<array<char>^>(aArray))
    {
        _AppendData(safe_cast<array<char>^>(aArray));
        return;
    }

    if (is_instance_of<array<short>^>(aArray))
    {
        _AppendData(safe_cast<array<short>^>(aArray));
        return;
    }

    // Do the same for the other ones

    throw gcnew System::NotSupportedException(System::String::Format("Unsupported type: {0}", T::typeid));
}

Upvotes: 5

Related Questions