I have done a number of Managed wrappers that deal with wrapping unmanged code for use in managed, but not so many that go the other way.
An experiment I was running involved using managed code to find directories and return them in a std vector. Long story short, I was messing with the following example and noticed a problem.
#include "Helper.h"
#include <msclr/marshal.h>
#include <msclr/marshal_cppstd.h>
using namespace msclr::interop;
using namespace System;
namespace CLIWrapper {
std::vector<std::string> Helper::GetDirs(const char* root)
{
std::vector<std::string> rval;
String^ path = gcnew System::String(root);
array<String^,1>^ dirs = System::IO::Directory::GetDirectories(path);
for (int i=0; i < dirs->Length; i++)
{
//this fails
std::string nativeString1(marshal_as<std::string>(dirs[i]));
//this fails as well
std::string nativeString2(marshal_as<std::string>((String ^ const)dirs[i]));
// this works
String ^mStr = dirs[i];
std::string nativeString(marshal_as<std::string>(mStr));
rval.push_back(nativeString);
}
return rval;
}
}
Failure for ‘nativeString1’ and ‘nativeString2’ is: error C2665: 'msclr::interop::marshal_as' : none of the 3 overloads could convert all the argument types
‘nativeString2’ uses the const because that is listed in one of the signatures of the marshal_as if you look at the details of the error.
Question is why does the ‘nativeString1’ conversion fail but ‘nativeString’ work? What are my eyes just refusing to notice?
Before it comes up in the response thread: Yes, I realize this isn’t the ‘best’ solution, that it isn’t platform independent, etc. I’m trying to focus on this specific error.
The compiler does not consider dirs[i]
to be a constant reference to the string (this is surprising to me too). However, you can get a temporary constant reference to the value without creating a new string handle by using the % operator, which will increment the reference count of the string at dirs[i]
:
// this works as well
auto nativeString1(marshal_as<std::string>(%*dirs[i]));