现代c++;,最好的方法是什么 P>从C范式到现代C++,我试图找出最好的C++替换可能是什么方式,旧的COM或设备表示变量:,和./P>

现代c++;,最好的方法是什么 P>从C范式到现代C++,我试图找出最好的C++替换可能是什么方式,旧的COM或设备表示变量:,和./P>,c++,windows,c++17,C++,Windows,C++17,在C的意义上,这些变体只是一个结构:一个键(GUID、PID对)、数据类型(只是一个UIN32)和一个缓冲区 typedef struct _DEVPROPERTY { DEVPROPCOMPKEY CompKey; DEVPROPTYPE Type; ULONG BufferSize; PVOID Buffer; } DEVPROPERTY, *PDEVPROPERTY; 有了这些,PnP和旧的Shell类型的COM组件可以通用地传递

在C的意义上,这些变体只是一个结构:一个键(GUID、PID对)、数据类型(只是一个UIN32)和一个缓冲区

typedef struct _DEVPROPERTY {
  DEVPROPCOMPKEY CompKey;
  DEVPROPTYPE    Type;
  ULONG          BufferSize;
  PVOID          Buffer;
} DEVPROPERTY, *PDEVPROPERTY;
有了这些,PnP和旧的Shell类型的COM组件可以通用地传递属性数据

<>我知道我可以在C++中重用这些C结构,但是如何用现代C++来实现呢?p> 我知道有一个似乎是一个很好的联合替代品,但我不认为它有助于类型发现

还有,它看起来像一个std::variant,但没有预定义类型

在任何情况下,我都不知道如何直接使用这些工具加载和重新发现数据类型。我想我仍然可以有一个类型定义为枚举的结构,并使用std:variant而不是union

例如,我仍然需要能够做这样的事情:

void DoSomething(DEVPROPERTY* prop)
{
    // assume we would be doing safe things with these pointers instead of directly derefing them and casting them :)
    switch (prop->Type) {
    case DEVPROP_TYPE_INT32:
        LONG val = *(LONG*)prop->Buffer;
        break;

    }
}
// Bit of boilerplate for combining lambdas
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

void DoSomething(const std::variant<long, std::string>& prop)
{
    std::visit(
        overloaded {
            [](long lng) { /* do whatever */ },
            [](const std::string& strng) { /* do whatever */ }
        },
        prop
    )
}
struct variant {
    enum {
        INT,
        STRING
    } type;
    union {
        int i;
        char* c;
    }
};
struct any {
    char* type;
    void* value;
};
一般来说,你应该为这类事情负责。它们提供对所包含值的类型安全访问,这是好的ol's“type enum和
void*
类型变量无法提供的

例如,问题中的
DoSomething
函数可以这样编写:

void DoSomething(DEVPROPERTY* prop)
{
    // assume we would be doing safe things with these pointers instead of directly derefing them and casting them :)
    switch (prop->Type) {
    case DEVPROP_TYPE_INT32:
        LONG val = *(LONG*)prop->Buffer;
        break;

    }
}
// Bit of boilerplate for combining lambdas
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

void DoSomething(const std::variant<long, std::string>& prop)
{
    std::visit(
        overloaded {
            [](long lng) { /* do whatever */ },
            [](const std::string& strng) { /* do whatever */ }
        },
        prop
    )
}
struct variant {
    enum {
        INT,
        STRING
    } type;
    union {
        int i;
        char* c;
    }
};
struct any {
    char* type;
    void* value;
};
std::any
更类似于这样的C结构:

void DoSomething(DEVPROPERTY* prop)
{
    // assume we would be doing safe things with these pointers instead of directly derefing them and casting them :)
    switch (prop->Type) {
    case DEVPROP_TYPE_INT32:
        LONG val = *(LONG*)prop->Buffer;
        break;

    }
}
// Bit of boilerplate for combining lambdas
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;

void DoSomething(const std::variant<long, std::string>& prop)
{
    std::visit(
        overloaded {
            [](long lng) { /* do whatever */ },
            [](const std::string& strng) { /* do whatever */ }
        },
        prop
    )
}
struct variant {
    enum {
        INT,
        STRING
    } type;
    union {
        int i;
        char* c;
    }
};
struct any {
    char* type;
    void* value;
};

使用
std::访问
-。有几个选项-最优雅的可以说是#4使用一堆Lamda。我觉得每种类型都有专门的模板将是最优雅的。当然,除非你不能改变接口,否则没有“现代C++范式”,<代码> STD::变体< /C> >和<>代码:STD::任何< <代码>都没有根本的不同于他们只是进行了一些封装,隐藏了关于值及其类型标记的实际存储方式的实现细节,并提供了一些额外的类型安全性。当我说“现代”时,我指的是当代或更现代的风格C++。对我来说,这意味着C++标准的最新版本,如C++ 11,或者C++ 17,它们使用匹配的当代标准库。我们的内部编译器支持大部分C++17标准以及即将推出的C++20的一些功能。我想应该理解,现代的C++并没有暗示像C++ 98或ANSI C风格的代码那样的旧版本。我的问题是关于StruouTUP会做什么?如果你遵循C++核心指导思想的精神,那会是什么样子?我可以用C风格写我所有的新C++代码,当然我们已经编写了很多代码,但是我将失去很多新C++特性的好处。