2017-01-23 90 views
2

我真的希望我可以使用C++(11)模板来实现这一点,但我在这里面临一些问题。所以我们有一个自定义指针对象,它可以是任何这些类型:它自己类型的对象列表/ int/a char/bool/long/double/char *或任何其他基本类型,它由该对象存储的标志。有一些全局方法可以从这个对象中获取特定类型的值。C++条件模板基于数据类型编译

现在,我的目的很简单。我知道我的情况,我的目标是这样的对象的列表,所以我想写这样的功能,因为它是一个常见的场景:

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转换为字符串或浮点转换为字符串转换的代码将失败。我真正想要的是一种在类型被检测为int而不是任何其他类型时编译代码的整型部分的方法。 我可以使用模板函数特化或重载,但是我认为它真的在这里打破了模板的目的,我可以为8种不同类型(例如List_To_String_Vector,List_To_Int_Vector等)编写8种不同的函数。

我也试过另一个黑客,使用reinterpret_cast < T * >上的每个返回类型的地址,然后解引用它来添加到向量。这种工作,但有编译器的警告,我认为这是未定义的行为。

有没有办法使这项工作正常?

谢谢!

+0

这看起来像一个非常糟糕的设计。如果你想要一个对象来处理多种类型,那么为什么不使用即将出现的C++ 17标准中的['std :: any'](http://en.cppreference.com/w/cpp/utility/any) ?或者如果你还没有它,那么[Boost any](http://www.boost。组织/ DOC /库/ 1_63_0/DOC/HTML/any.html)? –

+0

为什么您的'Func_ * Value'是单独的函数而不是单个模板或重载集? – Quentin

+0

@Quentin:由于遗留代码,并执行Scheme编程语言以C++互操作。 –

回答

4

The fundamental theorem of software engineering

我们可以通过引入额外的间接级别解决任何问题。

List_To_Vector做太多–两个转换从ObjectT,并填充vector;抽象出前者,解决方案变得自然。首先,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:

// 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<>可以使这个干净多了,如果你能负担得起的依赖。

+0

@PiyushSoni:如果您发布[MVCE](https://stackoverflow.com/help/mcve),我可以在回答中添加一个在线演示。 – ildjarn

2

让我们在您的List_To_Vector函数之下执行一个级别。我看到的问题是,你有不相关的Func_*Value功能的集合,让我们聚集他们下单,感知类型的模板一劳永逸:

template <class> 
struct valueGetter; 

template <> struct valueGetter<float> { static constexpr auto &get = Func_DoubleValue; }; 
template <> struct valueGetter<double> { static constexpr auto &get = Func_DoubleValue; }; 
template <> struct valueGetter<int> { static constexpr auto &get = Func_IntValue; }; 
// etc. 

现在List_To_Vector变得微不足道:

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) 
     vec.push_back(valueGetter<T>::get(Func_Next(list))); 

    return vec; 
} 

See it live on Coliru

0

我建议使用一个助手来推断正确的过载转换:

class convert 
{ 
    const Object& from; 
public: 
    explicit convert(const Object& from): from(from) {} 

    operator char()  const { return Func_CharValue(from); } 
    operator bool()  const { return Func_BoolValue(from); } 
    operator std::string() const { return Func_StringValue(from); } 
    operator const char*() const { return Func_StringValue(from); } 
    // ... 
}; 

// ... 

vec.push_back(convert(arg)); 

不需要模板。

这确实有一个缺点,就是不得不重复每个具体类型,即使它们使用相同的转换函数。但是你没有太多这样的东西。重载可以通过默认禁用的模板转换运算符来增强,但可用于重用常用转换函数的类型。

0

我会建议使用函数特化来包装每个调用,这样你可以精确控制每种类型发生的事情,例如,

template<typename T> T object_to(const Object& arg) { } 

template<> int   object_to(const Object& arg) { return Func_IntValue(arg); } 
template<> unsigned int object_to(const Object& arg) { return Func_IntValue(arg); } 
template<> std::string object_to(const Object& arg) { return Func_StringValue(arg); } 
template<> float  object_to(const Object& arg) { return Func_DoubleValue(arg); } 
template<> double  object_to(const Object& arg) { return Func_DoubleValue(arg); } 
template<> bool   object_to(const Object& arg) { return Func_BoolValue(arg); } 
template<> char   object_to(const Object& arg) { return Func_CharValue(arg); } 

然后给你的对象类的一些标准算法方法,并将其插入到以下几点:

1

我能玩吗?

我提出一个解决方案基于模板删除皈依功能

template <typename T> 
T getTValue (T const &, Object const &) = delete; 

,有些不是模板转换功能,具有相同签名,调用正确的Func_X_Value()功能;像

int getTValue (int const &, Object const & obj) 
{ return Func_IntValue(arg); } 

unsigned int getTValue (unsigned int const &, Object const & obj) 
{ return Func_IntValue(arg); } 

float getTValue (float const &, Object const & obj) 
{ return Func_DoubleValue(arg); } 

double getTValue (double const &, Object const & obj) 
{ return Func_DoubleValue(arg); } 

char * getTValue (char const * &, Object const & obj) 
{ return Func_StringValue(arg); } 

std::string getTValue (std::string const &, Object const & obj) 
{ return Func_StringValue(arg); } 

char getTValue (char const &, Object const & obj) 
{ return Func_CharValue(arg); } 

bool getTValue (bool const &, Object const & obj) 
{ return Func_BoolValue(arg); } 

第一个参数是没有用,只介绍选择的权利,不模板函数,所以for周期成为

for (int i = 0; i < listSize; ++i) 
    vec.push_back(getTValue(T(), arg)); 

模板中删除的功能介绍,以避免不必要的类型转换(例如:从short intint),如果有人试图拨打List_To_Vector()并输入错误T,则会在汇编阶段发生错误。

因此,通过实例,调用

std::vector<int> vi = List_To_Vector<int>(listContainingNumbers); 

应该是确定的,但打电话

std::vector<long> vl = List_To_Vector<long>(listContainingNumbers); 

因为getTValue<long>()被删除,没有一个getTValue(long const &, Object const &)没有模板函数。

p.s .:警告:未经测试的代码。