【问题标题】:C++ CLI error C3767: candidate function(s) not accessibleC++ CLI 错误 C3767:候选函数不可访问
【发布时间】:2010-10-31 03:19:54
【问题描述】:

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

我收到此错误:

candidate function(s) not accessible 

当我将 std::string 作为方法参数的一部分传递时。

这是确切的代码:

Lib 项目(编译为 .dll 项目)

//Lib.h

#pragma once

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

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

//Lib.cpp

#include "Lib.h"

Lib::Lib(void)
{
}

void Lib::Extract( std::string& data_ )
{
  data_.empty();
}

LibTest 项目(编译为 application.exe)

// LibTest.h

#pragma once

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

// LibTest.cpp

#include "LibTest.h"

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

int main()
{
  return 0;
}

编译器错误:

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

【问题讨论】:

  • 你可以使用string而不是char* @sivabudh @BenSchwen

标签: c++-cli


【解决方案1】:

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

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

默认情况下,本机类型在程序集之外是私有的 默认情况下,本机类型现在在程序集之外不可见。有关程序集外部类型可见性的详细信息,请参阅类型可见性。这一变化主要是由使用其他不区分大小写语言的开发人员在引用使用 Visual C++ 编写的元数据时的需求推动的。

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

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

basic_string 被编译为:

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

注意内部

不幸的是,您无法从不同的程序集中调用这样的方法。

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

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

void Extract2( std::exception& data_ );

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

#pragma make_public(std::exception)

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

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

【讨论】:

  • #pragma make_public 仅在它被声明到源代码文件结束时才有效。因此,当使用 #pragma make_public 指令时,有必要确保在另一个文件中没有使用相同的本机类型。在这种情况下,需要在所有使用本机类型的文件中应用 #pragma make_public。否则,链接器可能会报错LNK2022 metadata operation failed (80131195): Custom attributes are not compatible.
  • 如果我们想将“字符串”传递给函数@BenSchwehn,您可以使用char*,而不是使用string
【解决方案2】:

如果您只需要访问internal 方法,另一种解决方法就是将项目设置为Friend Assemblies,如下所示:

//库项目

#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项目

#pragma once

#using <Lib.dll> as_friend

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

【讨论】:

    【解决方案3】:

    除了上述解决方案之外,还可以将模板化类型子类化以获得非模板化类型,并将其定义包含在两个项目中,从而克服上述一些问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 2019-08-19
      相关资源
      最近更新 更多