views:

2688

answers:

3

I have a function which parses one string into two strings. In C# I would declare it like this:

void ParseQuery(string toParse, out string search, out string sort)
{
    ...
}

and I'd call it like this:

string searchOutput, sortOutput;
ParseQuery(userInput, out searchOutput, out sortOutput);

The current project has to be done in managed C++. I've tried

using System::Runtime::InteropServices;

...

void ParseQuery(String ^ toParse, [Out] String^ search, [Out] String^ sort)
{
    ...
}

but if I call it like this:

String ^ searchOutput, ^ sortOutput;
ParseQuery(userInput, [Out] searchOutput, [Out] sortOutput);

I get a compiler error, and if I call it like this:

String ^ searchOutput, ^ sortOutput;
ParseQuery(userInput, searchOutput, sortOutput);

then I get an error at runtime. How should I declare and call my function?

A: 

It's not supported. The closest you can get is ref

Granted you can fake it, but you lose a compile time check.

Greg Dean
OK... how would I declare and call a function with ref parameters in managed C++?
Simon
Not sure why this was voted down. When in fact it's not supported. Granted you can fake it, but you lose a compile time check. That's a pretty big deal imo
Greg Dean
+10  A: 

You can do this for reference types as:

void ReturnString([Out] String^% value)
{
   value = "Returned via out parameter";
}

// Called as
String^ result;
ReturnString(result);

And for value types as:

void ReturnInt([Out] int% value)
{
   value = 32;
}

// Called as
int result;
ReturnInt(result);

The % makes it a 'ref' parameter and the OutAttribute marks that it is only used for output values.

Bert Huijben
I don't think this is the same as the C# out modifier. For instance, in C# if a parameter it marked out and not assigned to, it results in a compiler error. Is this the same in your example?
Greg Dean
This is how C#s out parameters are implemented on the IL level: There is only a ref calling convention, used for ref and out in C#. The annotation with an OutAttribute makes it an out parameter.
Bert Huijben
See also: http://msdn.microsoft.com/en-us/magazine/cc164193.aspx#S2
Bert Huijben
The IL may be the same but from a language point of view C++ does not support the same thing as the C# out modifier. In the same way it doesn't support the notion of the using() statement (you create the same IL using try/finally, but you lose all the development benefits).
Greg Dean
You can easily reproduce using by not using ^ on a variable definition. MC++ automatically calls IDisposable. Dispose when the variable goes out of scope. (You just have to use . instead of -> and %variable if you pass the variable to a method)
Bert Huijben
And the compiler error provided by csc when an out parameter is not assigned to? How do you reproduce that?
Greg Dean
Thanks for this info!!
Matthew Bowen
A: 

Using Visual Studio 2008, this works and solved a major problem at my job. Thanks!

// header
namespace VHT_QMCLInterface {
   public ref class Client
   {
    public:
        Client();
        void ReturnInteger( int a, int b, [Out]int %c);
        void ReturnString( int a, int b, [Out]String^ %c);
   }
}

// cpp
namespace VHT_QMCLInterface {

    Client::Client()
    {

    }

    void Client::ReturnInteger( int a, int b, [Out]int %c)
    {
        c = a + b;
    }
    void Client::ReturnString( int a, int b, [Out]String^ %c)
    {
        c = String::Format( "{0}", a + b);
    }
}

// cs
namespace TestQMCLInterface
{
    class Program
    {
        VHT_QMCLInterface.Client m_Client = new VHT_QMCLInterface.Client();
        static void Main(string[] args)
        {
            Program l_Program = new Program();
            l_Program.DoReturnInt();
            l_Program.DoReturnString();
            Console.ReadKey();
        }

        void DoReturnInt()
        {
            int x = 10;
            int y = 20;
            int z = 0;
            m_Client.ReturnInteger( x, y, out z);
            Console.WriteLine("\nReturnInteger: {0} + {1} = {2}", x, y, z);
        }

        void DoReturnString()
        {
            int x = 10;
            int y = 20;
            String z = "xxxx";
            m_Client.ReturnString(x, y, out z);
            Console.WriteLine("\nReturnString: {0} + {1} = '{2}'", x, y, z);
        }
     }
}
Art Beall