工会成员可能没有构造函数,但`std :: pair`好吗?

Fra*_*ank 5 c++ constructor pod unions std-pair

union成员可能没有析构函数或构造函数.所以如果有一个构造函数Foo,我不能自己模板下面的类:MyClassMyClass

template<class T>
struct Foo {
  T val;
  Foo(T val_) : val(val_) {}
  size_t hash() const {
    union {T f; size_t s;} u = { val };
    return u.s;
  }
};
struct MyClass {
  bool a;
  double b;
  MyClass(bool a_, double b_) : a(a_), b(b_) {}
};
Run Code Online (Sandbox Code Playgroud)

如果我这样做,我得到这个错误:

member 'MyClass Foo<T>::hash() const 
[with T = MyClass]::<anonymous union>::f' with constructor 
not allowed in union
Run Code Online (Sandbox Code Playgroud)

为了解决这个问题,我创建MyClass了一个笨拙的构造函数,它首先复制了这个东西:

struct MyClass {
  bool a;
  double b;
};
MyClass createMyClass(bool a, double b) {
  MyClass m;
  m.a = a;
  m.b = b;
  return m;
}
Run Code Online (Sandbox Code Playgroud)

但我想知道是否有比使用此createMyClass功能更好的方法.构造函数会更高效,并且作为一个关键组件,MyClass并且Foo<MyClass>在我的代码中构建了数百万次.

的std ::对

我也有点惊讶,这可以使用std::pairunion:

Foo<std::pair<bool, double> > f2(std::make_pair(true, 3.12));
Run Code Online (Sandbox Code Playgroud)

据我所知,std::pair(见代码)有一个构造函数?

And*_*nck 10

编辑: 我原来的立场std::pair是错误的,不应该允许在工会中.要使类成为union的有效成员,它必须具有根据标准9.5.1的简单构造函数.从第12.1.5节开始,这是一个简单的构造函数的定义:

如果类X没有用户声明的构造函数,则隐式声明默认构造函数.一个隐式声明的默认构造函数是inline public其类的成员.构造函数是微不足道的 ,如果它是一个隐式声明的默认构造函数,如果:

  • 它的类没有虚函数,也没有虚基类
  • 它的所有直接基类都有琐碎的构造函数
  • 对于类类的所有非静态数据成员(或其数组),每个这样的类都有一个简单的构造函数

第20.2.2.2段规定以下构造函数必须成对使用:

pair(const T1& x, const T2& y);
Run Code Online (Sandbox Code Playgroud)

一旦提供了这个构造函数,就不会隐式声明默认构造函数.

这里有趣的是我的编译器(Visual Studio 2008)似乎给予std::pair特殊处理.如果我从std::pair实现中复制代码并将其放在我自己的命名空间foo中,那么联合会不起作用:)

namespace foo {
    template<class _Ty1, class _Ty2> struct pair {
        typedef _Ty1 first_type;
        typedef _Ty2 second_type;
        pair() : first(_Ty1()), second(_Ty2()) {
        }
    }
}

//This doesn't work in VC2008
union Baz {
    foo::pair<bool, double> a;
    int b;
}
//This works in VC2008
union Buz {
    std::pair<bool, double> a;
    int b;
}
Run Code Online (Sandbox Code Playgroud)

您的解决方案是解决此问题的常用方法.我通常在类名前加上一个C(构造的简称)来部分地模仿普通的构造函数语法,这在你的情况下会变成CMyClass(a, b).

正如Steve和Matthieu指出的那样,你并没有使用非常好的哈希函数.首先,没有真正的保证(我认为,如果我错了请纠正我),f并且s在联合中甚至会部分占用相同的内存空间,其次即使它们在实践中可能会共享第一个min(sizeof(s), sizeof(f))字节,这意味着MyClass你只是对值的一部分进行哈希处理.在这种情况下,您将哈希值的值bool a,在这种情况下有两个选项:

  1. 您的编译器使用int内部表示形式,bool在这种情况下,您的哈希函数将只返回两个值,一个用于true,一个用于false.
  2. 您的编译器char用作内部表示bool.在这种情况下,该值可能至少填充sizeof(int)为零,在这种情况下,您具有与1.相同的情况,或者在MyClass分配时堆栈上的任何随机数据,这意味着您获得相同输入的随机哈希值.

如果您需要按整个值散列,T我会将数据复制到像Steve建议的临时缓冲区中,然后使用此处讨论的可变长度散列函数之一.

  • `std :: pair`没有一个简单的构造函数 - 它没有隐式声明.GCC(4.1.2)在我试图将一个人加入工会时给出同样的错误; 也许有些编译器比较宽松. (2认同)