C++ CLI error C3767: candidate function(s) not accessible

流过昼夜 提交于 2019-11-27 05:04:43

The problem is that std::string will compile as a internal (non public) type. This is actually a change in VS 2005+:

http://msdn.microsoft.com/en-us/library/ms177253(VS.80).aspx:

Native types are private by default outside the assembly Native types now will not be visible outside the assembly by default. For more information on type visibility outside the assembly, see Type Visibility. This change was primarily driven by the needs of developers using other, case-insensitive languages, when referencing metadata authored in Visual C++.

You can confirm this using Ildasm or reflector, you will see that your extract method is compiled as:

public unsafe void Extract(basic_string<char,std::char_traits<char>,std::allocator<char> >* modopt(IsImplicitlyDereferenced) data_)

with basic_string being compiled as:

[StructLayout(LayoutKind.Sequential, Size=0x20), NativeCppClass, MiscellaneousBits(0x40), DebugInfoInPDB, UnsafeValueType]
internal struct basic_string<char,std::char_traits<char>,std::allocator<char> >

Note the internal.

Unfortunately you are then unable to call a such a method from a different assembly.

There is a workaround available in some cases: You can force the native type to be compiled as public using the make_public pragma.

e.g. if you have a method Extract2 such as:

void Extract2( std::exception& data_ );

you can force std::exception to be compiled as public by including this pragma statement beforehand:

#pragma make_public(std::exception)

this method is now callable across assemblies.

Unfortunately make_public does not work for templated types (std::string just being a typedef for basic_string<>) I don't think there is anything you can do to make it work. I recommend using the managed type System::String^ instead in all your public API. This also ensures that your library is easily callable from other CLR languages such as c#

if you simply must access the internal methods another work around would be making the projects as Friend Assemblies like that:

//Lib Project

#pragma once

//define LibTest as friend assembly which will allow access to internal members
using namespace System;
using namespace System::Runtime::CompilerServices;
[assembly:InternalsVisibleTo("LibTest")];

public ref class Lib
{
 public:
  Lib(void);

 public:
  void Extract( std::string& data_ );
};

//LibTest Project

#pragma once

#using <Lib.dll> as_friend

ref class LibTest
{
  public:
    LibTest(void);
};

In addition to the solutions described above, one can subclass the templated type to obtain a non-templated type, and include its definition in both projects, thus overcoming some of the problems mentioned above.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!