为什么从我的 class 外部调用它时会出现转换错误?

Why do I get a conversion error when calling this from outside my class?

我有一个 class 我正在尝试为其编写一些单元测试,但我遇到了转换错误:

1>c:\projects\myproj\unittests\UnitTest_MyClass.h(60): error C2664: 'MyClass::MyFunc' : cannot convert parameter 1 from 'GenericCollections::CircularBuffer<T> ^' to 'GenericCollections::CircularBuffer<T> ^'
1>          with
1>          [
1>              T=const MyProj::DataPacket ^
1>          ]
1>          and
1>          [
1>              T=MyProj::DataPacket ^const 
1>          ]

Class 正在测试中(只是一个片段):

public ref class MyClass
{
protected:
    double MyFunc(GenericCollections::CircularBuffer<const MyProj::DataPacket^>^ data, int &firstIndex, int &lastIndex);

单元测试(只是一个片段):

[Test]
public ref class UnitTest_MyClass : public MyClass
{
public:
    [Test]
    void Test_0001_MyFunc()
    {
        GenericCollections::CircularBuffer<const MyProj::DataPacket^>^ data = nullptr; // This will eventually be populated with test data
        int firstIndex = 0;
        int lastIndex = data->Length-1;

        double funcResult = MyFunc(data, firstIndex, lastIndex); // causes error C2664
    }

我可以在测试中的 class 中以相同的方式调用此方法并且它工作正常,那么为什么当我从单元测试中调用它时它会失败?

with
[
    T=const Anchor::DataPacket ^
]
and
[
    T=Anchor::DataPacket ^const 
]

看起来编译器混淆了对 const 对象的引用和对对象的 const 引用。 C2664 的错误描述页面没有显式显示传递 const 引用集合时发生的情况。我想我会尝试从模板中删除常量。

问题中缺少一个重要的细节,但可以推断出来。这无法编译,因为您正在通过程序集引用而不是#include 导入类型定义。您对该代码进行单元测试的预期方式。

您必须记住 const 关键字是一个问题,CLR 完全忽略了这个概念。它只有在强制执行时才有意义,当您的代码被另一种托管语言(如 VB.NET 或 C#)使用时,这种情况不会发生。没有任何类似于 const 它在本机 C++ 中的使用方式的语言。

CLR 中的元数据确实允许语言通过 [modopt] 构造向变量和参数类型添加任意属性。 C++/CLI 编译器在发出 Func<> 的元数据时使用它,您可以通过 ildasm.exe:

看到它
   MyFunc(class GenericCollections.CircularBuffer`1<
          class DataPacket modopt([mscorlib]System.Runtime.CompilerServices.IsConst)
       > data,
       // etc...

编辑以适合,注意类型参数上发出的 [modopt]。然而,这还不足以完全表达 const 可以在本机 C++ 中应用的各种方式。 data 参数可以是 const T^ dataT^ data constconst T^ data const。不是一个 [modopt].

可以表达的东西

您可能会争辩说这是编译器缺陷,但事实并非如此,此限制是故意的。他们确实让编译器足够聪明,可以注意到 const 在这里有歧义,并生成适当的错误消息。

好吧,对此您无能为力。当您#include 类型定义时,这将不是问题,编译器随后就足够了解声明。也许你可以重新调整你的项目,尽管它不是很实用。对于这个问题,我通常的建议是放弃 const 在托管代码中有用的想法。事实并非如此,C++/CLI 是一种互操作语言,这种代码的普通使用者不了解有关 const 的 bean,因此不会强制执行它。