常量工会成员有什么用?他们不是毫无意义吗?

What's the use of const union members? Aren't they quite pointless?

本文关键字:他们 毫无意义 成员 什么 常量      更新时间:2023-10-16

在这个答案的评论中,Koushik提出了一个非常有效的观点。

采取以下措施:

union U
{
    int x;
    const T y;
};

(我选择T这样这里没有通用的布局兼容性初始序列,这意味着每个[C++11: 9.5/1]在任何给定时间只能有一个成员处于活动状态。

由于任何时候只有一个成员可以"活动"(通过写入它来激活),并且初始化后无法写入y,这不是毫无意义吗?我的意思是,y只能在第一次写入x之前读取,并且只有当y是初始化的成员时。

我缺少一些用例吗?或者这确实是语言特征的毫无意义的融合?

(这在前面已经提到过)

下面是一个引用语义类型的人为示例,您只想授予const访问权限。该union用于从"类型擦除"函数返回的类似变体的数据类型。

#include <memory>
template<class T>
struct reference_semantics
{
public:
    reference_semantics(T* p ) : m(p) {}
    int observe() const { return *m; }
    void change(T p) { *m = p; }
private:
    T* m;
};
struct variant
{
    enum T { INT, DOUBLE } type;
    union U
    {
        reference_semantics<int> const i;
        reference_semantics<double> const d;
        U(int* p) : i(p) {}
        U(double* p) : d(p) {}
    } u;
};
#include <iostream>
std::ostream& operator<<(std::ostream& o, variant const& v)
{
    switch(v.type)
    {
        case variant::INT:
            return o << "INT: "<<v.u.i.observe();
        case variant::DOUBLE:
            return o << "DOUBLE: "<<v.u.d.observe();
    }
}
#include <string>
variant type_erased_access(std::string name)
{
    // imagine accesses to a map or so
    static double dval = 42.21;
    static int ival = 1729;
    if(name == "Lightness") return { variant::DOUBLE, &dval };
    else return { variant::INT, &ival };
}
int main()
{
    variant v0( type_erased_access("Lightness") );
    std::cout << v0 << "n";
    variant v1( type_erased_access("Darkness") );
    std::cout << v1 << "n";
}

现在想象一下,不是intdouble,而是使用更大的数据类型,并且reference_semantics数据类型实际上提供了比仅返回值更多的功能。

您甚至可能希望为某些参数返回reference_semantics<some_type> const,但为其他参数返回普通int。在这种情况下,您的union甚至可能有常量和非常量成员。

它确实有用途:

1)用于提供类似const_cast的技术。从某种意义上说,x = const_cast<...>(y).

2) 处理模板时,有时您需要数据类型的const版本,以便匹配其他参数类型。

我已经看到(1)在针对传统接口进行编程时使用)。

不经常使用联合,但这可能是这种情况:

#include <iostream>
class Accessor;
union Union
{
    private:
    friend class Accessor;
    int write;
    public:
    const int read;
    Union() : read(0) {}
};
class Accessor  {
    public:
    static void apply(Union& u, int i) { u.write = i; }
};
int main() {
    Union u;
    // error: ‘int Union::write’ is private
    // u.write = 1;
    std::cout << u.read << 'n';
    Accessor::apply(u, 1);
    std::cout << u.read << 'n';
}

注:从9.5个工会

注意:为了简化使用 联合:如果标准布局联合包含多个标准布局 共享公共初始序列 (9.2) 的结构,如果对象 此标准布局联合类型包含标准布局之一 结构体,允许检查任何 标准布局结构构件;请参阅 9.2.— 尾注 ]

如果联合表示某种方法/算法的结果的一部分,那么它可能是有意义的。 但在这种情况下,我会将两个值都设为const

union T
{
    const int x;
    const int y;
};