C ++ CLI error C3767: функции-кандидаты недоступны - PullRequest
13 голосов
/ 04 июня 2009

Я новичок в C ++ CLI из неуправляемого мира C ++.

Я получаю эту ошибку:

candidate function(s) not accessible 

когда я передаю std :: string как часть аргумента метода.

Вот точный код:

Lib Project (скомпилированный как .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

Ответы [ 3 ]

25 голосов
/ 04 июня 2009

Проблема в том, что 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_)

с базовой_строкой, компилируемой как:

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

Обратите внимание на внутренний .

К сожалению, вы не можете вызвать такой метод из другой сборки.

В некоторых случаях доступен обходной путь: Вы можете принудительно скомпилировать нативный тип как общедоступный, используя прагму make_public.

например. если у вас есть метод Extract2, такой как:

void Extract2( std::exception& data_ );

вы можете принудительно скомпилировать std :: exception как public, предварительно включив этот прагматический оператор:

#pragma make_public(std::exception)

этот метод теперь доступен для всех сборок.

К сожалению, make_public не работает для шаблонных типов (std :: string просто является typedef для basic_string <>) Я не думаю, что вы можете что-то сделать, чтобы это сработало. Я рекомендую использовать управляемый тип System :: String ^ во всех ваших общедоступных API. Это также гарантирует, что ваша библиотека легко вызывается из других языков CLR, таких как c #

4 голосов
/ 19 августа 2013

, если вам просто нужно получить доступ к internal методам, другой обходной путь сделает проекты как Friend Assemblies , например:

// 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

#pragma once

#using <Lib.dll> as_friend

ref class LibTest
{
  public:
    LibTest(void);
};
2 голосов
/ 18 июня 2014

В дополнение к решениям, описанным выше, можно получить подкласс шаблонного типа для получения не шаблонного типа и включить его определение в оба проекта, тем самым преодолевая некоторые из проблем, упомянутых выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...