基于数据类型的C ++条件模板编译 [英] C++ Conditional Templates Compilation based on data type
问题描述
我真的希望我可以使用C ++(11)模板实现这一目标,但是我在这里遇到了一些问题.因此,我们有一个自定义指针对象,该对象内部可以是以下任何一种类型:它自己类型/int/a char/bool/long/double/char *或任何其他原始类型的对象的列表,由该对象存储的标志.有一些全局方法可以从此对象获取特定类型的值.
I was really hoping I could achieve this using C++ (11) Templates, but I'm facing some problem here. So we have a custom pointer object which internally could be of any of these types: a list of objects of its own type/an int/a char/bool/long/double/char* or any other primitive type, and it's decided by a flag that this object stores. There are global methods to get values of specific types from this object.
现在,我的目的很简单.我知道对于我来说,我的对象是这样的对象的列表,所以我想编写这样的函数,因为这是一种常见的情况:
Now, my purpose is simple. I know that for my case, my object is a list of such objects, so I wanted to write a function like this as it's a common scenario:
template <typename T>
std::vector<T> List_To_Vector(Object& list)
{
std::vector<T> vec;
int listSize = Func_Size(list);
for (int i = 0; i < listSize; ++i)
{
//let's say this function gives list items one by one
Object arg = Func_Next(list);
if (std::is_same<T, int>::value || std::is_same<T, unsigned int>::value)
vec.push_back((T)Func_IntValue(arg));
else if (std::is_same<T, float>::value || std::is_same<T, double>::value)
vec.push_back((T)Func_DoubleValue(arg));
else if (std::is_same<T, std::string>::value || std::is_same<T, char*>::value)
vec.push_back((T)Func_StringValue(arg)); //Func_StringValue returns char*, so conversion to std::string should work
else if (std::is_same<T, bool>::value)
vec.push_back(Func_BoolValue(arg));
else if (std::is_same<T, char>::value)
vec.push_back(Func_CharValue(arg));
vec.push_back(val);
}
return vec;
}
int main()
{
Object listContainingStrings = GetListOfNames();
Object listContainingNumbers = GetListOfNumbers();
std::vector<string> vec1 = List_To_STD_Vector<string>(listContainingStrings);
std::vector<int> vec2 = List_To_STD_Vector<int>(listContainingNumbers);
return 0;
}
问题是,C ++在这里抱怨,因为它试图编译采用T = std :: string的代码,并且将int转换为字符串或将float转换为字符串将失败.我真正想要的是一种在检测到类型为int而不是其他任何类型时,编译代码的int部分的方法.我可以使用模板函数专门化或重载,但是我认为这确实违背了模板的目的,我可以为8种不同类型(例如List_To_String_Vector,List_To_Int_Vector等)编写8个不同的函数.
The problem is, C++ complains here as it tries to compile the code taking T = std::string, and int to string or float to string conversions would fail. What I really wanted here was a way to compile the int part of the code when the type is detected as int, and not of any other type. I can use Template function specialization or overloading, but then I think it really defeats the purpose of templates here and I could just write 8 different functions for 8 different types (e.g. List_To_String_Vector, List_To_Int_Vector and so on).
我还尝试了另一种方法,使用reinterpret_cast< T *>在每个返回类型的地址上,然后将其解引用以添加到向量中.这种方法有效,但是有编译器警告,我认为这是未定义的行为.
I also tried another hack, using reinterpret_cast<T*> on the address of the each return types, and then dereferencing it to add to the vector. That kind of worked, but has Compiler warnings and I think that's undefined behavior.
有没有办法使它正常工作?
Is there a way to make this work properly?
谢谢!
推荐答案
我们可以通过引入额外的间接级别来解决任何问题.
We can solve any problem by introducing an extra level of indirection.
List_To_Vector
做得太多–从 Object
转换为 T
,并填充 vector
;将前者抽象出来,解决方案就变得自然了.首先, List_To_Vector
:
List_To_Vector
is doing too much – both conversion from Object
to T
, and filling a vector
; abstract out the former and the solution becomes natural. First, List_To_Vector
:
template<typename T>
std::vector<T> List_To_Vector(Object& list) {
std::vector<T> vec;
for (int i = 0, listSize = Func_Size(list); i < listSize; ++i) {
vec.push_back(Object_To<T>(Func_Next(list)));
}
return vec;
}
现在,您可以根据需要重载或专门化 Object_To
.这是使用SFINAE的一种方法:
Now you can just overload or specialize Object_To
as necessary. Here's one way, using SFINAE:
// not strictly necessary, but reduces noise a bit
template<bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template<typename T>
auto Object_To(Object arg)
-> enable_if_t<std::is_same<T, int>{} || std::is_same<T, unsigned>{}, T>
{
return (T)Func_IntValue(arg);
}
template<typename T>
auto Object_To(Object arg)
-> enable_if_t<std::is_same<T, float>{} || std::is_same<T, double>{}, T>
{
return (T)Func_DoubleValue(arg);
}
template<typename T>
auto Object_To(Object arg)
-> enable_if_t<std::is_same<T, std::string>{} || std::is_same<T, char*>{}, T>
{
return (T)Func_StringValue(arg);
}
template<typename T>
auto Object_To(Object arg) -> enable_if_t<std::is_same<T, bool>{}, T>
{
return Func_BoolValue(arg);
}
template<typename T>
auto Object_To(Object arg) -> enable_if_t<std::is_same<T, char>{}, T>
{
return Func_CharValue(arg);
}
使用类似 boost ::如果您负担得起依赖项,fusion :: map<>
可以使此操作更加简洁.
Using something like boost::fusion::map<>
can make this much cleaner if you can afford the dependency.
这篇关于基于数据类型的C ++条件模板编译的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!