更好的转换功能

时间:2012-04-02 17:15:52

标签: c++ templates

我在C ++ 0x框架中有各种类,并且想要编写函数来在它们之间进行转换。例如:

struct Foo { float v; };
struct Bar { int i; };
struct Tar { float p, q; };

void Convert(const Foo& x, Bar& y) { y.i = static_cast<int>(x.v); }
void Convert(const Tar& x, Foo& y) { y.v = x.p + x.q; }

这只是一个例子。有很多“小”课程。并非所有转换功能都有意义。

此外,有些类基本上表现得像STL容器,应该“继承”这些转换函数。

void Convert(const std::vector<Foo>& cx, std::vector<Bar>& cy) { ... }
void Convert(const std::vector<Tar>& cx, std::vector<Bar>& cy) { ... }

不,我正在寻找一种简单的方法来定义这些功能。我试过了:

template<typename X, typename Y>
void Convert(const std::vector<X>& cx, std::vector<Y>& cy) {
   cy.resize(cx.size());
   for(std::size_t i=0; i<cx.size(); i++) {
     Convert(cx[i], cy[i]);
   }
}

这很有效。

然而,有了这样的设置,我必须写

std::vector<X> cx = { ... };
std::vector<Y> cy;
Convert(cx, cy);
// when not specifying the type, one needs to use this form f(X, &Y)

使用类似

的设置
template<typename X, typename Y>
std::vector<Y> Convert(const std::vector<X>& cx) {
   std::vector<Y> cy(cx.size());
   for(std::size_t i=0; i<cx.size(); i++) {
     cy[i] = Convert(cx[i]);
   }
   return cy;
}

一个人必须写

std::vector<X> cx = { ... };
std::vector<Y> cy = Convert<X,Y>(cx);
// can I avoid specifying the source type with this form?

当然,在某些时候需要提到目标类型,但源类型由函数参数定义。我不想一次又一次地提到它。

是否有一种优雅的通用方法来处理这种转换函数?

编辑问题以澄清

4 个答案:

答案 0 :(得分:1)

您是否考虑过使用ctors:

struct Bar {
   int i;

   explicit Bar(Foo const &f) : i(static_cast<int>(f.v)) {}
};

然后你可以这样做:

Bar x = static_cast<Bar>(some_foo);

您是否真的想要明确地提出这个问题可能会有疑问。如果你消除它(允许隐式转换),转换一个向量就变得微不足道了:

std::vector<foo> foos;

// code to populate foos ...

std::vector<Bar> bars((foos.begin()), foos.end());

至于是否要明确表达,问题是你是否可能意外地从Foo转换到Bar,让某些事情发生你真正不想要的事情。对于转换为bool之类的问题,这是一个非常常见的问题,但从一个用户定义的类型转换为另一个类型的问题则更少。在这种情况下,关闭explicit可以方便且合理安全。

答案 1 :(得分:1)

为什么不简单地为此目的使用构造函数?

explicit Bar(const Foo& x) : i(static_cast<int>(x.v)) {}

答案 2 :(得分:0)

由于返回值优化,您不需要使用out参数,只需使用返回值:

void Convert(const X& x, Y& y);

变为:

Y Convert(const X& x);

所以现在你可以在表达中使用它。

另请考虑使用转换构造函数转换运算符

Y::Y(const X&);
X::operator Y();

这些将允许类型之间的隐式转换(如果这是您想要的 - 否则您可以将它们声明为显式)。

对于处理STL容器,请使用迭代器范围:

template<class FwdIterator>
Y Convert(FwdIterator begin, FwdIterator end);

在这种风格中,它不仅与所有STL容器兼容,而且还与原始指针范围兼容。

另请注意,如果声明隐式转换构造函数或转换运算符,则可以使用std :: copy:

vector<X> xs = ...;
vector<Y> ys;
copy(xs.begin(), xs.end(), back_inserter(ys.begin()));

这会在将元素从xs转换为ys时隐含地调用用户定义的转换。

答案 3 :(得分:0)

实际上我发现了如何做到这一点。通过重新排序模板参数

template<typename Y, typename X>
std::vector<Y> ConvertTo(const std::vector<X>& cx) {
   std::vector<Y> cy(cx.size());
   for(std::size_t i=0; i<cx.size(); i++) {
     cy[i] = Convert(cx[i]);
   }
   return cy;
}

可以写

std::vector<Y> cy = ConvertTo<Y>(cx);

并且编译器自动推断第二个模板类型以进行输入。不错的功能!