3

我一直在开发一些 DLL 实用程序项目,以避免在其他项目中重复代码,以及我尚未尝试过的功能、算法和测试。其中一个项目是 C++/CLI,我仍在学习的语言,所以这个问题可能听起来很愚蠢。因为我有 C++/CLI、F# 和 C# 中的库项目,所以我使用 C# 控制台应用程序来测试它们。它不适用于 C++/CLI 项目,因此我创建了一个 C++/CLI 控制台测试项目。它从来没有用过,当我更改原始 DLL C++ 的名称时,引用没有更新。当我(最终)发现问题时,我更改了 .vcxproj 文件,使 using 指令成为可能,作为一种方法,但不适用于模板类Apont<typename T>,它是某种内部指针,但与 .NET 类型不同System::IntPtr, 使用类型的值T*而不是void*.

我还发现(从本网站的一篇文章中)我必须在项目内部使用我想在外部使用的东西,否则这些东西想要在元数据中发出。因此,为此目的,我在静态实用程序中有一个无用的静态方法:

static void Funcionalidades()
{
    int i = 10;

    Apont<int> a2 = Apont<int>(i);            // stack
    Apont<int> ^a3 = gcnew Apont<int>(i);     // heap CLR

}

尽管如此,它还是行不通。这是我在 C++/CLI 测试项目中的主要方法:

int main(array<System::String ^> ^args)
{
    int y(10);
    Apont<int> a = Apont<int>(y);

    Console::ReadKey();
    return 0;
}

以下是错误(我知道它可以用智能感知错误进行编译,但无论如何我都会展示它们):

error C2065: 'Apont' : undeclared identifier
error C2062: type 'int' unexpected
IntelliSense: identifier "Apont" is undefined
IntelliSense: type name is not allowed
IntelliSense: expected an expression

为什么会出现这些错误?我该如何纠正它们?

我将不胜感激任何回答或回复。

编辑(澄清):

  • 这些错误不会发生在FuncionalidadesDLL 项目中的方法上,而是发生在测试项目中的主方法上,即 DLL 之外。
  • 我将所有内容都写在头文件中;我的意思是不是每个头文件都有各自的 .cpp 文件,尽管所有头文件都包含在至少一个 .cpp 文件中。
  • 更多关于Apont
    • Apont是一个模板(因为在内部使用了 T* 并且“不允许对泛型类型参数进行间接引用”)。
    • Apont有一个复制构造函数,所以Apont<int> a = Apont<int>(someInt)应该可以工作;
    • Apont<int> a(someInt)不工作;
    • Apont是某种内部指针;而且我没有发布整个代码,因为它不相关,我必须翻译变量的名称,它可能有我可以轻松修复的错误,但这只会分散你的注意力。

NTH EDIT(其中'n'是我不知道的数字):

Apont你抱怨了很久的代码:

    template<typename T> public ref class Apont sealed : public IDisposable
    {
        bool eliminado;
        T *pointer;

        /*void Dispose(bool tudo)
        {
            if (!eliminado)
            {
                if (tudo)
                {
                    ~Apont();
                }
                else
                {
                    !Apont();
                }
            }
        }*/
        !Apont() // finalizador: limpa os recursos "unmanaged"
        {
            delete pointer;
            pointer = nullptr;
            eliminado = true;
        }

    public:
        Apont(T &valor)
        {
            pointer = &valor;
            eliminado = false;
            ErroSeNulo = false;
            ErroSeEliminado = true;
        }
        Apont(T &valor, bool erroSeEliminado, bool erroSeNulo)
        {
            pointer = &valor;
            eliminado = false;
            ErroSeEliminado = erroSeEliminado;
            ErroSeNulo = erroSeNulo;
        }
        Apont(Apont<T> %outroApont)
        {
            this->pointer = &outroApont
        }

        property bool ErroSeEliminado;
        property bool ErroSeNulo;
        property T Valor
        {
            T get()
            {
                if (pointer != nullptr)             
                    return *pointer;
                else if (eliminado && ErroSeEliminado)
                    throw gcnew ObjectDisposedException("O objeto já foi pelo menos parcialmente eliminadao.");
                else if (ErroSeNulo)
                    throw gcnew NullReferenceException();
                else
                    return 0;
            }
        }

        /*
        Apont operator ~(/*T valor* /)
        {
            // este operador tem de ser declarado fora desta classe 
        }*/
        T operator !(/*Apont apont*/)
        {
            return Valor;
        }
        void operator =(Apont<T> outroApont)
        {
            pointer = outroApont;
            ErroSeEliminado = outroApont.ErroSeEliminado;
            ErroSeNulo = outroApont.ErroSeNulo;             
        }
        template<typename U> void operator =(Apont<U> outroApont)
        {
            pointer = safe_cast<T>(outroApont.pointer);
            ErroSeEliminado = safe_cast<T>(outroApont.ErroSeEliminado);
            ErroSeNulo = safe_cast<T>(outroApont.ErroSeNulo);
        }
        /*
        void operator =(T *&outroPointer)
        {
            pointer = outroPointer;
        }
        template<typename U> void operator =(U *&outroPointer)
        {
            pointer = safe_cast<T>(outroPointer);
        }*/
        void operator =(T *outroPointer)
        {
            pointer = outroPointer;
        }
        template<typename U> void operator =(U *outroPointer)
        {
            pointer = safe_cast<T>(outroPointer);
        }


        ~Apont() // destruidor: limpa todos os recursos
        {               
            this->!Apont();
        }

        // Error C2605: 'Dispose': this method is reserved within a managed class
        // O código será gerado automaticamente a partir do finalizador e do destrutor
    };

    template<typename T> Apont<T> operator ~(T &valor)
    {
        return gcnew Apont<T>(valor);
    }
4

5 回答 5

3

您出现的错误通常是缺少类声明。这通常发生在标头中的代码被标头保护之后。

这是怎么发生的?

如果您在 Funcionalidades 中包含 Apont 标头,然后在 Apont 中包含 Funcionalidades 标头,那么您就有麻烦了。发生这种情况是因为 Funcionalidades 标头缺少 Apont 声明,以防您在包含 Funcionalidades 之前将 Apont 包含在您的 main 中。

然后你第一次包含 Apont,它将启用标题保护。然后它将包括Funcionalidades,其中也包括Apont。因为已经启用了标头保护功能 Funcionalidades 标头将没有 Apont 声明。同时 Apont 的声明甚至还没有在 Apont 的相应头文件中开始。在这里,由于 main 中的这个问题,您无法编译,因为在库编译时您没有这样的依赖项。

我如何解决它?

在 cpp 代码中的 Funcionalidades 实现中移动 Apont 的使用,保持头文件没有依赖关系。

于 2013-04-12T05:51:53.193 回答
1

我必须在项目内部使用我想在外部使用的东西

如果这是真的,你有没有在任何地方调用过静态函数?未调用的函数可能会被优化掉。

于 2013-04-10T18:20:51.753 回答
1

它只是抱怨它不知道“Apont”。我也不知道它是什么,你没有发布它的代码。只需声明它的任意版本:

generic<typename T>
public ref class Apont {
    T value;
public:
    Apont(T init) : value(init) {}
};

static void Funcionalidades()
{
    int i = 10;

    Apont<int> a2(i);                      // stack
    Apont<int> ^a3 = gcnew Apont<int>(i);  // heap CLR

}

请注意“a2”的更改代码,避免引用类型的复制构造函数。再次主要:

    Apont<int> a(y);
于 2013-03-09T16:33:49.827 回答
1

名称空间的 using 语句是否会丢失?确保您的 main 方法中有正确的 using 语句。还要确保您添加了一个引用,以便包含 main 方法的项目引用包含 Apont 的项目。

于 2013-04-17T05:39:09.963 回答
1

很抱歉花了这么长时间才回复您:我有几点可以帮助您解决问题。- 模板类被声明为密封:这意味着您不能将其用作基类(与您使用模板类的主要原因相反)。至少它不需要,所以它可能值得删除。- 其次,更重要的是,在 C++ 中,模板是在编译时评估的,因此,由于您没有声明指定的实例,因此不会评估 Apont 并且它不会编译到 DLL 中。要启用特定版本的模板类,您可以在UtilCMM.h文件末尾添加以下内容:

  • class template Apont<int>;
  • class template Apont<float>;
  • class template Apont<double>;

这是因为在 C++ 中,模板在编译时由预处理器扩展,就像宏一样,但是只有显式使用的版本才会在编译时处理:这是一个很大的优势和劣势。我一直找到的解决方案(与其他 C++ 程序员一致)是:

  • 明确实例化您需要在 dll 中导出的版本
  • 提供带有模板的头文件,然后您将代码分发给的任何人都可以使用该文件

如果还有其他方法可以达到相同的效果,我还没有遇到过,很想知道,唉,这些都是模板的局限性。

那么当您编译时,您应该拥有三个可用的特定版本。只需为您希望包含在 DLL 中的每种类型添加更多内容。抱歉,我之前没有发现这一点,当我看到完整的代码时,他们都跳了出来,现在如果我可以让项目编译,我可以自己尝试更改(我的 VS 版本不加载你的 vcproj 文件版本,典型的)。

于 2013-04-19T07:25:41.890 回答