问题
VTK has typedefs for basic types (float, int, double, etc.), and it assigns an integer per type. They are specified here.
The function GetDataType(), for example in vtkDataArray returns an integer that corresponds to one of the types.
I would like to compare that integer with the basic data types (float, int, double).
Is there a way of doing so, easily ?
The usage I have of this is a template class which parameter T is a scalar. I want to check if the scalar point data of a dataset has the same data type as T.
For now, what I do, is a type size comparison :
vtkDataArray *scalars = image->GetPointData()->GetScalars();
if(scalars->GetDataTypeSize() != sizeof(T))
{
std::cerr<<"Incompatible types"<<std::endl;
}
But obviously, float and int are both of size 4, so it doesn't really work.
Any ideas ?
回答1:
After gathering information from a few places, I concluded there is no way to write it simply without creating the mapping myself between the two lists of types.
So, here is the most elegant way I found to do that :
I used the idea of norisknofun's map, but I inverted it.
I didn't use std::type_index() because it seems you can get the hash_code directly from the result of typeid().
I put this mapping in a function that transform basic type to VTK type, because it can serve other purposes than just comparison (see my other post).
#include <vtkType.h>
int GetVTKType(std::size_t hash_code)
{
static std::map<std::size_t, long> typeMap;
if(typeMap.empty())
{
typeMap[typeid(void).hash_code()] = VTK_VOID;
typeMap[typeid(char).hash_code()] = VTK_CHAR;
typeMap[typeid(signed char).hash_code()] = VTK_SIGNED_CHAR;
typeMap[typeid(unsigned char).hash_code()] = VTK_UNSIGNED_CHAR;
typeMap[typeid(short).hash_code()] = VTK_SHORT;
typeMap[typeid(unsigned short).hash_code()] = VTK_UNSIGNED_SHORT;
typeMap[typeid(int).hash_code()] = VTK_INT;
typeMap[typeid(unsigned int).hash_code()] = VTK_UNSIGNED_INT;
typeMap[typeid(long).hash_code()] = VTK_LONG;
typeMap[typeid(unsigned long).hash_code()] = VTK_UNSIGNED_LONG;
typeMap[typeid(float).hash_code()] = VTK_FLOAT;
typeMap[typeid(double).hash_code()] = VTK_DOUBLE;
typeMap[typeid(std::string).hash_code()] = VTK_STRING;
typeMap[typeid(long long).hash_code()] = VTK_LONG_LONG;
typeMap[typeid(unsigned long long).hash_code()] = VTK_UNSIGNED_LONG_LONG;
typeMap[typeid(int64_t).hash_code()] = VTK___INT64;
typeMap[typeid(uint64_t).hash_code()] = VTK_UNSIGNED___INT64;
}
return typeMap[hash_code];
}
Therefore, to compare a vtk data type, and a basic type (my template parameter T), I do :
vtkDataArray *scalars = image->GetPointData()->GetScalars();
if(scalars->GetDataType() != GetVTKType(typeid(T).hash_code()))
{
std::cerr<<"Incompatible types"<<std::endl;
}
Or if I want a nice comparison function as norisknofun did it, I can do :
template < class T >
bool is_same(long vtkType)
{
return vtkType != GetVTKType(typeid(T).hash_code())
}
// somewhere.cpp
if(!is_same<T>(scalars->GetDataType()))
{
std::cerr<<"Incompatible types"<<std::endl;
}
回答2:
I guess you have to elaborate your own mapping. Your compiler must be c++11 compliant with RTTI activated but now most of modern compilers support this feature.
I dont know what is the c++ equivalent of 'bit', 'id_type' and 'opaque' types...
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <cstdint>
#include <string>
#include <map>
// copy from vtk header, use #include <vtkType.h> instead
#define VTK_VOID 0
#define VTK_BIT 1
#define VTK_CHAR 2
#define VTK_SIGNED_CHAR 15
#define VTK_UNSIGNED_CHAR 3
#define VTK_SHORT 4
#define VTK_UNSIGNED_SHORT 5
#define VTK_INT 6
#define VTK_UNSIGNED_INT 7
#define VTK_LONG 8
#define VTK_UNSIGNED_LONG 9
#define VTK_FLOAT 10
#define VTK_DOUBLE 11
#define VTK_ID_TYPE 12
#define VTK_STRING 13
#define VTK_OPAQUE 14
#define VTK_LONG_LONG 16
#define VTK_UNSIGNED_LONG_LONG 17
#define VTK___INT64 18
#define VTK_UNSIGNED___INT64 19
// vtktypes
typedef long vtktypes ;
// standard c++ types
typedef std::size_t mytypes ;
typedef std::map< vtktypes, mytypes> map_t;
template < class T >
bool is_same(vtktypes x)
{
static std::map< vtktypes, mytypes> _map;
if(_map.empty())
{
_map[VTK_VOID ] = std::type_index(typeid(void)).hash_code();
//_map[VTK_BIT ] = std::type_index(typeid(void)).hash_code();
_map[VTK_CHAR ] = std::type_index(typeid(char)).hash_code();
_map[VTK_SIGNED_CHAR ] = std::type_index(typeid(signed char)).hash_code();
_map[VTK_UNSIGNED_CHAR ] = std::type_index(typeid(unsigned char)).hash_code();
_map[VTK_SHORT ] = std::type_index(typeid(short)).hash_code();
_map[VTK_UNSIGNED_SHORT ] = std::type_index(typeid(unsigned short)).hash_code();
_map[VTK_INT ] = std::type_index(typeid(int)).hash_code();
_map[VTK_UNSIGNED_INT ] = std::type_index(typeid(unsigned int)).hash_code();
_map[VTK_LONG ] = std::type_index(typeid(long)).hash_code();
_map[VTK_UNSIGNED_LONG ] = std::type_index(typeid(unsigned long)).hash_code();
_map[VTK_FLOAT ] = std::type_index(typeid(float)).hash_code();
_map[VTK_DOUBLE ] = std::type_index(typeid(double)).hash_code();
//_map[VTK_ID_TYPE ] = type_index(typeid()).hash_code();
_map[VTK_STRING ] = std::type_index(typeid(std::string)).hash_code();
//_map[VTK_OPAQUE ] = type_index(typeid(void)).hash_code();
_map[VTK_LONG_LONG ]= std::type_index(typeid(long long)).hash_code();
_map[VTK_UNSIGNED_LONG_LONG]= std::type_index(typeid(unsigned long long)).hash_code();
_map[VTK___INT64 ]= std::type_index(typeid(int64_t)).hash_code();
_map[VTK_UNSIGNED___INT64 ]= std::type_index(typeid(uint64_t)).hash_code();
}
map_t::iterator it = _map.find(x);
return (it != _map.end()) && it->second == std::type_index(typeid(T)).hash_code();
}
int main()
{
std::cout << "is same ? " << is_same<char>(2) << std::endl ;
std::cout << "is same ? " << is_same<std::string>(13) << std::endl ;
return 0;
}
In your case, you can use it like that :
vtkDataArray *scalars = image->GetPointData()->GetScalars();
if(!is_same<T>(scalars->GetDataTypeSize()))
{
std::cerr<<"Incompatible types"<<std::endl;
}
来源:https://stackoverflow.com/questions/36476714/compare-vtk-data-types-and-basic-data-types