C++ CLI错误C3767:无法访问候选函数

siv*_*udh 13 c++-cli

我是来自非托管C++世界的C++ CLI的新手.

我收到这个错误:

candidate function(s) not accessible 
Run Code Online (Sandbox Code Playgroud)

当我传递一个std :: string作为方法参数的一部分.

这是确切的代码:

Lib Project(编译为.dll项目)

//Lib.h

#pragma once

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

public:
  void Extract( std::string& data_ );
};
Run Code Online (Sandbox Code Playgroud)

//Lib.cpp

#include "Lib.h"

Lib::Lib(void)
{
}

void Lib::Extract( std::string& data_ )
{
  data_.empty();
}
Run Code Online (Sandbox Code Playgroud)

LibTest项目(编译为application.exe)

// LibTest.h

#pragma once

ref class LibTest
{
public:
  LibTest(void);
};
Run Code Online (Sandbox Code Playgroud)

// LibTest.cpp

#include "LibTest.h"

LibTest::LibTest(void)
{
  Lib^ lib = gcnew Lib;
  lib->Extract( std::string("test") );
}

int main()
{
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译器错误:

1>------ Build started: Project: LibTest, Configuration: Debug Win32 ------
1>Compiling...
1>LibTest.cpp
1>.\LibTest.cpp(7) : error C3767: 'Lib::Extract': candidate function(s) not accessible
Run Code Online (Sandbox Code Playgroud)

Ben*_*ehn 25

问题是std :: string将编译为内部(非公共)类型.这实际上是VS 2005+的变化:

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

默认情况下,默认情况下,本机类型在程序集外部默认为私有类型.有关程序集外部类型可见性的更多信息,请参阅类型可见性.在引用Visual C++中创建的元数据时,此更改主要由使用其他不区分大小写的语言的开发人员的需求驱动.

您可以使用Ildasm或反射器确认这一点,您将看到您的提取方法编译为:

public unsafe void Extract(basic_string<char,std::char_traits<char>,std::allocator<char> >* modopt(IsImplicitlyDereferenced) data_)
Run Code Online (Sandbox Code Playgroud)

将basic_string编译为:

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

注意内部.

不幸的是,你无法从不同的程序集调用这样的方法.

在某些情况下有一种解决方法:您可以使用make_public pragma强制将本机类型编译为公共类型.

例如,如果您有方法Extract2,例如:

void Extract2( std::exception& data_ );
Run Code Online (Sandbox Code Playgroud)

您可以通过事先包含此pragma语句来强制将std :: exception编译为public:

#pragma make_public(std::exception)
Run Code Online (Sandbox Code Playgroud)

此方法现在可以跨程序集调用.

不幸的是,make_public对于模板化类型不起作用(std :: string只是basic_string <>的typedef)我不认为你可以做任何事情来使它工作.我建议在所有公共API中使用托管类型System :: String ^.这也确保您的库可以从其他CLR语言轻松调用,例如c#

  • **#pragma make_public** 仅从声明点到源代码文件末尾有效。因此,当使用 **#pragma make_public** 指令时,有必要确保其他文件中不使用相同的本机类型。在这种情况下,有必要在使用本机类型的所有文件中应用**#pragma make_public**。否则,链接器可能会报告错误_LNK2022元数据操作失败(80131195):自定义属性不一致。_ (2认同)