【问题标题】:Check if void* to Object with static_cast is successful使用 static_cast 检查 void* 到 Object 是否成功
【发布时间】:2018-09-24 15:10:30
【问题描述】:

我正在开发一个将从 C# 调用的 C++ 插件。我尝试移植的 API 带有数百个函数,其中大多数只是重载,名称相同,但数据类型不同,如 intfloatchar

我不想一遍又一遍地编写相同的代码,但在 C++ 和 C# 端使用不同的数据类型,我想使用一个带有通用指针的函数重载。我的目标是使用static_castvoid*intfloat 然后char 并使用哪个先成功。

C++ 端的一个简单测试函数:

void calculate(void* input1, void* input2)
{
    float *i1 = static_cast<float*>(input1);
    if(i1==NULL)
    std::cout<<"Bad"<<std::endl;
    else
    std::cout<<*i1<<std::endl;
}

int main()
{
   int input1 = 5;
   int input2 = 10;

   calculate(&input1,&input2);

   return 0;
}

这应该输出“BAD”,但它似乎显示“7.00649e-45”,我认为这是一种未定义的行为。 static_cast 失败了,我不知道如何检查它是否成功。检查它是否是 NULL 在这种情况下没有帮助。

是否可以检查void* 到带有static_cast 的对象是否成功?如果有,怎么做?

注意

这不是this 问题的重复。我不想从void* 中找出对象的类型。我只想检查转换或static_cast 是否成功。就是这样。

【问题讨论】:

  • 存储typeid。或者更好的是,使用std::anystd::variant
  • 强制转换没有失败,但取消引用其结果是未定义的。您或编译器都无法确定 void* 的“原始”类型。
  • static_cast 的意思是“即使它被声明为void*,我知道它确实是float*。”因此,如果它不是浮子*,它就在你的肩膀上。
  • 所以这个void*实际上是从C#进来的(作为System.IntPtr)?
  • 你可能不走运。没有办法以某种方式检索 C++ 中的类型(至少我知道)。您必须在 C# 中执行类型检查,然后调用您的 C++ 函数,以便可以适当地封送数据。

标签: c++ pointers casting void-pointers


【解决方案1】:

static_cast 不执行类型检查,不能用于可靠地检索类型。此外,传入函数的是void* 指针,此时类型信息会丢失,甚至dynamic_cast 也无济于事。因此,即使在纯 C++ 中,如果没有模板,这也是一个难以解决的问题。 void* 指针实际上是 C# System.IntPtr 的事实使问题更加复杂,据我所知,没有足够强大的互操作层来检索原始类型(即使是原始类型)。

像这样的问题就是为什么要发明像 cog 这样的样板代码生成器的原因。那里有很多,您可能需要进行一些研究以找到最适合您需求的一个。 Cog 通过插入嵌入在 C++(或 C#,或其他)文件中的代码生成脚本来工作,并且可以注入到您的构建过程中。您可能会发现它值得(相对较小的)时间投入(与手动生成样板代码相比)。

【讨论】:

    【解决方案2】:

    使用static_cast 来恢复函数参数的类型是不合适的,因为转换将在编译时从void*float* 进行。由于存在这种类型的转换链,因此编译器不会抱怨,并且在执行过程中,转换本身不会失败,即使不能保证其结果。

    这同样适用于调用计算函数时从int*void* 的转换。

    也许对于这种情况,您可以考虑使用模板函数来利用 C++ 的元编程特性。

    这是一个开始的片段:

    template <class T*>
    void calculate(T* a, T* b) {
        // your implementation here
    }
    

    编辑

    如果您只需要为几种类型(如 int、float、double 等)导出模板函数,您可以考虑在您的库的一个 cpp 文件中为每种类型添加一个模板特化,其中包含声明了模板函数。

    这是int* 类型的示例。

       template __declspec(dllexport) calculate<int*>(int* a, int* b);
    

    【讨论】:

    • 我也想过模板,但不能使用它,因为在构建为 DLL 时无法导出模板函数。就像我在问题中提到的那样,最终函数将从 C# 调用。
    • 是的,使用模板可以轻松解决这个问题,而且,有人想到了std::any。但这不是答案,我想。
    • @Constructor 您是否阅读了我关于由于无法在 dll 插件中导出模板函数而无法执行此操作的评论? std::any 也不是一个选项。
    • @Programmer 我明白了,我的意思是人们应该解决你的问题,而不是改变实现它的方式。
    • @G.Giordano 我看到了您的编辑,但这也无济于事。 calculate&lt;int*&gt;(int* a, int* b) 只能取 int。这就是我使用void* 的原因,它是一个通用指针。每个函数大约有 5 个重载,其中大约有 900 个。我问了这个问题,以便我可以使用 void* 并避免在 C++ 和 C# 端一次又一次地声明每个 5x 并编写相同的代码。如果不是几个月,这将需要很长时间才能完成。
    猜你喜欢
    • 2015-05-04
    • 2013-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-07
    • 2014-05-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多