从visual c+;中的无序映射继承时,模板参数的sizeof()不正确+; 当声明继承自 STD::unOrdEdMultMux/Cuff>的类模板时,在VisualC++ 2015中运行时,模板参数的大小错误。p>
下面的代码在使用从visual c+;中的无序映射继承时,模板参数的sizeof()不正确+; 当声明继承自 STD::unOrdEdMultMux/Cuff>的类模板时,在VisualC++ 2015中运行时,模板参数的大小错误。p>,c++,inheritance,visual-studio-2015,sizeof,unordered-map,C++,Inheritance,Visual Studio 2015,Sizeof,Unordered Map,下面的代码在使用 g++ -std=c++11 test.cpp 输出以下内容: OUTSIDE: sizeof(my_key_type) = 12, sizeof(my_value_type) = 24 INSIDE: sizeof(my_key_type) = 12, sizeof(my_value_type) = 24 INSIDE(WTF?): sizeof(key_type) = 12, sizeof(value_type) = 24 但是在64位机器上的Visual C++ 20
g++ -std=c++11 test.cpp
输出以下内容:
OUTSIDE: sizeof(my_key_type) = 12, sizeof(my_value_type) = 24
INSIDE: sizeof(my_key_type) = 12, sizeof(my_value_type) = 24
INSIDE(WTF?): sizeof(key_type) = 12, sizeof(value_type) = 24
但是在64位机器上的Visual C++ 2015中,我得到:
OUTSIDE: sizeof(my_key_type) = 12, sizeof(my_value_type) = 24
INSIDE: sizeof(my_key_type) = 12, sizeof(my_value_type) = 24
INSIDE(WTF?): sizeof(key_type) = 12, sizeof(value_type) = 40
如果我没有继承自std::unordered_map
,那么在Ubuntu和VC2015上一切都很好。我错过了什么
提前感谢您的帮助-以下是代码:
#include <stdio.h>
#include <string.h>
#include <string>
#include <unordered_map>
class my_key_type {
unsigned int _int1;
unsigned int _int2;
unsigned short _short1;
unsigned short _short2;
public:
bool operator == (const my_key_type &other_key) const {
return (memcmp(this, &other_key, sizeof(my_key_type)) == 0);
};
};
namespace std {
template <> struct hash<my_key_type> {
std::size_t operator()(const my_key_type &key) const {
return std::hash<string>()(std::string((const char *)&key, sizeof(my_key_type)));
};
};
};
class my_value_type {
bool _flag;
unsigned long long _count1;
unsigned long long _count2;
};
#define INHERITS_FROM_UNORDERED_MAP 1
#if (INHERITS_FROM_UNORDERED_MAP == 0)
template <typename key_type, typename value_type> class kv_map {
#else
template <typename key_type, typename value_type> class kv_map : public std::unordered_map<key_type, value_type> {
#endif
public:
void test_print() {
printf("INSIDE: sizeof(my_key_type) = %ld, sizeof(my_value_type) = %ld\n", sizeof(my_key_type), sizeof(my_value_type));
printf("INSIDE(WTF?): sizeof(key_type) = %ld, sizeof(value_type) = %ld\n", sizeof(key_type), sizeof(value_type));
};
};
int main() {
printf("OUTSIDE: sizeof(my_key_type) = %ld, sizeof(my_value_type) = %ld\n", sizeof(my_key_type), sizeof(my_value_type));
kv_map<my_key_type, my_value_type> map;
map.test_print();
};
#包括
#包括
#包括
#包括
将my_key_类型分类{
无符号整数_int1;
无符号整数_int2;
无符号短路_short1;
无符号短路_short2;
公众:
布尔运算符==(常数我的键类型和其他键)常数{
return(memcmp(this,&other_key,sizeof(my_key_type))==0);
};
};
名称空间标准{
模板结构哈希{
std::size\u t运算符()(常量my\u key\u type&key)常量{
返回std::hash();
};
};
};
分类我的值类型{
布卢旗;
无符号长-长计数1;
无符号长-长计数2;
};
#定义从\u无序\u映射1继承\u
#if(从\u无序\u映射继承\u==0)
模板类kv_图{
#否则
模板类kv_图:公共标准::无序_图{
#恩迪夫
公众:
无效测试_打印(){
printf(“内部:sizeof(my_key_type)=%ld,sizeof(my_value_type)=%ld\n”,sizeof(my_key_type),sizeof(my_value_type));
printf(“内部(WTF?):sizeof(键类型)=%ld,sizeof(值类型)=%ld\n,sizeof(键类型),sizeof(值类型));
};
};
int main(){
printf(“外部:sizeof(my_key_type)=%ld,sizeof(my_value_type)=%ld\n”,sizeof(my_key_type),sizeof(my_value_type));
千伏地图;
map.test_print();
};
std::无序映射
有一个名为value\u type的类型
value_type std::pair<const Key, T>
value\u类型std::pair
几乎可以肯定的是,你正在接受这一点——因为这也包括关键数据
更改模板类型的名称,看看会发生什么。
std::unordered\u map
有一个名为value\u type
value_type std::pair<const Key, T>
value\u类型std::pair
几乎可以肯定的是,你正在接受这一点——因为这也包括关键数据
更改模板类型的名称,看看会发生什么。问题是,imho,类型的查找优先于
键类型
和值类型
您选择使用已存在于std::unordered_map
类中的两个类型名
using value_type = pair<const K, V>;
如果您从
无序映射中强制使用值类型
,您将得到40个字节。问题是,imho,类型键类型
和值类型
的查找优先
您选择使用已存在于std::unordered_map
类中的两个类型名
using value_type = pair<const K, V>;
如果您强制使用无序映射中的值类型
,您将得到40个字节。我相信这是VS无法进行两阶段查找的一种情况
非模板基类的名称将隐藏派生类模板参数的名称。例如:
class A
{
public:
int T:
};
template<typename T>
class B : A
{
// here T will mean A::T and not the template parameter
};
A类
{
公众:
int T:
};
样板
B类:A
{
//这里T表示A::T,而不是模板参数
};
另一方面,如果基类是一个模板,那么在第1阶段名称查找过程中,它的本地名称是未知的,因此名称必须绑定到该点上可见的内容
template<typename X>
class A
{ };
template<>
class A<int>
{
using T = float;
};
template<typename T>
class B : A<T>
{
// here a possible A::T is not visible at phase 1
// so T must mean B::T
};
模板
甲级
{ };
样板
甲级
{
使用T=浮动;
};
样板
B类:A
{
//在第1阶段,可能的a::T不可见
//所以T一定是指B::T
};
众所周知,VC++在模板实例化之前不会执行名称查找。当时它知道实际参数和实际基类型,并且显然将案例2视为案例1。我相信这是VS无法执行两阶段查找的一种情况
非模板基类的名称将隐藏派生类模板参数的名称。例如:
class A
{
public:
int T:
};
template<typename T>
class B : A
{
// here T will mean A::T and not the template parameter
};
A类
{
公众:
int T:
};
样板
B类:A
{
//这里T表示A::T,而不是模板参数
};
另一方面,如果基类是一个模板,那么在第1阶段名称查找过程中,它的本地名称是未知的,因此名称必须绑定到该点上可见的内容
template<typename X>
class A
{ };
template<>
class A<int>
{
using T = float;
};
template<typename T>
class B : A<T>
{
// here a possible A::T is not visible at phase 1
// so T must mean B::T
};
模板
甲级
{ };
样板
甲级
{
使用T=浮动;
};
样板
B类:A
{
//在第1阶段,可能的a::T不可见
//所以T一定是指B::T
};
众所周知,VC++在模板实例化之前不会执行名称查找。当时它知道实数参数和实数基类型,并且显然将案例2视为案例1。我猜这与编译器在bool
和以下unsigned long
之间添加的填充有关。此外,我会检查从声明虚拟函数的类继承时添加到类中的V-table指针。不同的编译器可能会为此使用不同的实现(尽管我怀疑这是本例中的问题)。不是为继承而设计的,它没有虚拟析构函数。或者更确切地说,它没有任何虚拟函数,但它缺少虚拟析构函数,这将使您在后面遭受最大的损失。如果您想继承接口的一部分,那么您可以使用私有继承。遵循Joachim的说法:我不需要吗nherit fromstd::unordered\u map
-包含它。(使用has-a,而不是is-a)。我猜它与编译器在bool