【问题标题】:c++-cli: Why does calling a generic function fail, when it calls another generic function?c++-cli:当调用另一个泛型函数时,为什么调用泛型函数会失败?
【发布时间】:2015-10-18 14:37:09
【问题描述】:

以下代码是我的程序和类重现失败的重要部分:

using namespace System;

generic <class T>
ref class gener
{
public:
  void func1g (T value)
  {
    Console::WriteLine (value);
    int iValue = static_cast<int>(value);
    if (iValue <= 0) return;
    func2 ();
  }

  void func2 ()
  {
    T value = (T)(Object^)0;
    func1g (value);
  }
};

int main()
{
  gener<int>^ g = gcnew gener<int>;
  int iValue = 1;
  g->func1g (iValue);  // <<=== System.TypeLoadException

  return 0;
}

当调用func1g 时,我得到一个System.TypeLoadException。我只是不明白为什么。
是不是因为func2没有泛型参数?

这是完整的错误消息(德语,但它只是说“未处理的异常”和“无法加载”;没有详细信息):

C# 中的等效代码有效:

public class gener<T>
{
  public void func1g(T value)
  {
    Console.WriteLine(value);
    int iValue = Convert.ToInt32(value);
    if (iValue <= 0) return;
    func2();
  }

  public void func2()
  {
    T value = (T)(object)0;
    func1g(value);
  }
};

internal class Program
{
  private static void Main()
  {
    gener<int> g = new gener<int>();
    int iValue = 1;
    g.func1g(iValue);

    return;
  }
}

编辑

我找到了一种“解决方法”,请参阅下面的答案,但我不知道为什么会这样。
如果有人能向我解释此失败的原因和解决方法的功能,我将不胜感激。

编辑 2
如果您想重现此内容:我使用 VS 2008 SP1。
我希望它不再像我上一期那样与编译器相关,尽管我个人认为这很有可能......

【问题讨论】:

  • 异常究竟是发生在g-&gt;func1g (iValue); 还是发生在func1g 的某个地方?
  • @crashmstr:它恰好发生在这一行。函数本身没有“打开”。
  • 异常消息中是否有任何内容?可能有帮助:What could be causing a System.TypeLoadException?
  • @crashmstr:如果您还没有注意到:请查看编辑和我的答案。
  • static_cast&lt;int&gt;(value) 绝对等同于Convert.ToInt32(value)。那将是Convert::ToInt32(value),我猜你应该在这里使用那个。在 C# 中,static_cast&lt;int&gt;(value) 的等价物是 (int)value,它一开始就无法编译。泛型不是模板:)

标签: generics c++-cli


【解决方案1】:

经过一些测试,我刚刚找到了解决这个特定问题的方法:

我需要定义func1g如下:

generic <class T>
void func1g (T value)
{
  ...
}

但我不明白为什么。
两种方式(问题中的代码和此解决方案)都可以正常编译,但第一种方式会产生运行时异常,请参阅帖子。

还有一个问题:
请注意,上面的func1g 是在同一位置声明和定义的!
我的原始代码分为 .h 和 .cpp,如下所示:

generic <class T>
ref class gener
{
public:
  generic <class T>
  void func1g (T value);

  void func2 ()
  {
    T value = (T)(Object^)0;
    func1g (value);
  }
};

generic <class T>
void gener<T>::func1g (T value)
{
  Console::WriteLine (value);
  int iValue = static_cast<int>(value);
  if (iValue <= 0) return;
  func2 ();
}

现在编译器用error C2511: 'void gener&lt;T&gt;::func1g(T)': overloaded member function not found in 'gener&lt;T&gt;'抱怨cpp

因此我继续玩弄(这确实是反复试验)并找到了一个我完全不明白的可行解决方案:

using namespace System;

generic <class T>
ref class gener
{
public:
  generic <class T2>
  void func1g (T2 value);

  void func2 ()
  {
    T value = (T)(Object^)0;
    func1g (value);
  }
};

generic <class T>
generic <class T2>
void gener<T>::func1g (T2 value)
{
  Console::WriteLine (value);
  int iValue = static_cast<int>(value);
  if (iValue <= 0) return;
  func2 ();
}

int main()
{
  gener<int>^ g = gcnew gener<int>;
  int iValue = 1;
  g->func1g (iValue);

  return 0;
}

谁能给我解释一下?
我实际上不知道双重generic 定义是可能的。

【讨论】:

    【解决方案2】:

    这是 C# 代码(顺便说一句,它在 C# 中也被破坏了,除非 TSystem.Int32System.Int32,你应该使用 default(T)),这在 C++/CLI 中是不合理的。

      void func2 ()
      {
          T value = (T)(object)0;
          func1g(value);
      }
    

    仅仅因为 C++/CLI 编译器接受完全相同的代码,并不意味着它做同样的事情!

    object 是 C# 中的关键字,我不知道您在 C++/CLI 中添加了哪些宏以使其编译(通常不会),但等效的 C++/CLI 类型是 System::Object^ (注意手柄)。

    无论如何,您只需要一个 T 类型的值初始化项,在 C++ 中写为

    T value{};
    

    【讨论】:

    • 最初我使用不同的方式将 int 转换为泛型。在制作 c# 程序时,我随后对 c++cli 程序进行了调整,以使该部分相同。但是我已经写了这篇文章的这一部分,包括代码,并从错误的 c# prog 中复制了这一行。我的错,编辑。我没有使用任何宏。另请参阅我的答案,它包含工作代码。 int32 BTW 只是为了避免无限循环和堆栈溢出。原始程序在那部分有所不同。 3 年后 c++cli 我知道 ^ 句柄 ;-) 但感谢初始化信息!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    相关资源
    最近更新 更多