我试图学习有关C ++ / CLI以便在C ++和C#之间互操作的更多信息。我有3个项目
- 带有.net 4.7的C#exe
- C ++ / CLI混合dll和
- 本机C ++ 17 dll。
我在编译C ++ / CLI项目时遇到问题。我之前已经工作过,所以应该正确设置所有内容,但是由于我做了一些严重的代码更改,因此不再起作用。
在我的C ++ / CLI项目中,我有一个提供一些基本函数调用的类:
// ManagedApi.cpp
public ref class ManagedApi
{
public:
static void SayHello()
{
Bindings::SayHello::invokeIfBound();
}
static int Add(int x,int y)
{
return Bindings::Add::invokeIfBound(x,y).value_or(-1);
}
static void Greet(System::String^ name)
{
Bindings::Greet::invokeIfBound(
msclr::interop::marshal_as<std::string>(name)
);
}
static int accumulate(int x)
{
if (!Bindings::accumulate::isBound())
throw gcnew System::InvalidOperationException("No accumulator bound");
return Bindings::accumulate::invoke(x);
}
static void SayGoodbye()
{
Bindings::SayGoodbye::invokeIfBound();
}
};
这些函数绑定是类型别名:
// Bindings.hpp
namespace Bindings
{
using SayHello = UnmanagedFunctionBinding<0,void()>;
using Greet = UnmanagedFunctionBinding<1,void(std::string const&)>;
using SayGoodbye = UnmanagedFunctionBinding<2,void()>;
using Add = UnmanagedFunctionBinding<3,int(int,int)>;
using accumulate = UnmanagedFunctionBinding<4,int(int)>;
}
下面的函数包装基本上是一个std::function
单例。
// UnmanagedFunctionBinding.hpp
template <auto ID,typename TReturn,typename... TArgs>
class UnmanagedFunctionBinding<ID,TReturn(TArgs...)>
{
public:
UnmanagedFunctionBinding() = delete;
using FunctionType = std::function<TReturn(TArgs...)>;
GLUE_API static constexpr decltype(ID) Id = ID;
GLUE_API static bool isBound() noexcept
{
return static_cast<bool>(s_func);
}
GLUE_API static TReturn invoke(TArgs... args)
{
return s_func(std::forward<TArgs>(args)...);
}
GLUE_API static auto invokeIfBound(TArgs... args) ->
std::conditional_t<std::is_same_v<TReturn,void>,void,std::optional<TReturn>>
{
if constexpr (std::is_same_v<TReturn,void>)
{
if (isBound())
s_func(std::forward<TArgs>(args)...);
}
else
{
return isBound()
? std::make_optional(s_func(std::forward<TArgs>(args)...))
: std::nullopt;
}
}
GLUE_API static void bind(std::function<TReturn(TArgs...)> func) noexcept
{
s_func = std::move(func);
}
GLUE_API static void unbind() noexcept
{
s_func = nullptr;
}
private:
static FunctionType s_func;
};
在模仿类似的行为(基本上访问了用作不同功能的查找表的全局映射)之前,我使用了名称空间功能,但效果很好。但是由于我移到类而不是函数,所以我在混合dll中收到链接器错误。上面的所有代码都位于同一个C ++ / CLI项目中。
自从我进入链接阶段以来,编译似乎一直有效,但显然我的ManagedApi.obj
在这里遇到了一些麻烦:
ManagedApi.obj:错误LNK2020:无法解析的令牌(0A00022A)“专用:静态类std :: function胶水:: UnmanagedFunctionBinding :: s_func“(?s_func @?$ UnmanagedFunctionBinding @ $ MH02 $$ A6AHHH @ Z $$ V @ Glue @@ 0V?$ function @ $$ A6AHHH @ Z @ std @@ A)
或
ManagedApi.obj:错误LNK2001:未解析的外部符号“私人:静态类std :: function胶水:: UnmanagedFunctionBinding :: s_func”(?s_func @?$ UnmanagedFunctionBinding @ $ MH01 $ $ A6AXXZ $$ V @ Glue @@ 0V?$ function @ $$ A6AXXZ @ std @@ A)
仅举几例。在这一点上,我没有跨越任何DLL边界,所以我不知道为什么不应该链接此代码。我以为可能有一些特殊的C ++ / CLI机制,所以我添加了一个本地源文件(Bindings.cpp
),在其中我明确实例化了所有使用的模板(包括std::function
和{{1} }。但是现在,此源文件引发了相同的链接器错误。为什么?
从错误消息中我发现它与std::string
成员有关系,但是我不知道问题出在哪里。当它们似乎解决相同的问题时,为什么会有两个不同的错误UnmanagedFunctionBinding::s_func
和LNK2020
?