基于数据类型的C ++条件模板编译 [英] C++ Conditional Templates Compilation based on data type

查看:56
本文介绍了基于数据类型的C ++条件模板编译的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的希望我可以使用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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆