c ++模板转换
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/714213/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
c++ template casting
提问by Steve
I'm a little lost in how to cast templates. I have a function foo which takes a parameter of type ParamVector<double>*
. I would like to pass in a ParamVector<float>*
, and I can't figure out how to overload the casting operator for my ParamVector
class, and Google isn't helping me that much. Does anyone have an example of how to do this? Thanks.
我对如何投射模板有点迷茫。我有一个函数 foo ,它接受一个类型为 的参数ParamVector<double>*
。我想传入一个ParamVector<float>*
,但我不知道如何为我的ParamVector
班级重载转换运算符,而 Google 并没有给我太多帮助。有没有人有如何做到这一点的例子?谢谢。
EDIT: Adding some code, sorry I'm an idiot and didn't phrase the original question well at all;
编辑:添加一些代码,对不起,我是个白痴,根本没有很好地表达原始问题;
template<class T> class ParamVector
{
public:
vector <T> gnome;
vector <T> data_params;
}
template<class T> class ParamVectorConsumer
{
public:
ParamVector<T> test;
}
ParamVector<float> tester;
ParamVectorConsumer<double> cons;
cons.ParamVector = tester
will fail to compile. I would like to know how to write it so that I can cast the float version of tester to a ParamVector double. Thanks
将无法编译。我想知道如何编写它,以便我可以将测试器的浮点版本转换为 ParamVector double。谢谢
EDIT2: Casting was the wrong word. I don't mind writing extra code, I just need to know how to get this to be accepted by the compiler so that I can write some sort of conversion code.
EDIT2:铸造是错误的词。我不介意编写额外的代码,我只需要知道如何让编译器接受它,以便我可以编写某种转换代码。
回答by bayda
I'm not sure but maybe you need some like this:
我不确定,但也许你需要这样的:
template< typename TypeT >
struct ParamVector
{
template < typename NewTypeT >
operator ParamVector< NewTypeT >()
{
ParamVector< NewTypeT > result;
// do some converion things
return result;
}
template< typename NewTypeT >
ParamVector( const ParamVector< NewTypeT > &rhs )
{
// convert
}
template < typename NewTypeT >
ParamVector& operator=( const ParamVector< NewTypeT > &rhs )
{
// do some conversion thigns
return *this;
}
};
ParamVector< double > d1;
ParamVector< float > f1;
f1 = d1;
You can choose use conversion operator or operator= - I've provided both in my example.
您可以选择使用转换运算符或运算符 = - 我在我的示例中提供了两者。
回答by tpdi
Well, you can't. Each different actual template parameter, makes an entirely new class, which has no* relation inheritance relation with any any other class, with a diffent actual argument, made from that template.
嗯,你不能。每个不同的实际模板参数,构成一个全新的类,该类与任何其他类没有*关系继承关系,具有不同的实际参数,由该模板构成。
No relationship. Well, except that each provides the same interface, so that inside a templateyou can handle then the same.
没有关系。好吧,除了每个提供相同的接口,以便在模板中您可以处理然后相同。
But neither the static types or the dynamic types have any relation.
但是静态类型和动态类型都没有任何关系。
Let me drop back here, and explain.
让我回到这里,解释一下。
When I declare a pointer to classtype, like
当我声明一个指向类类型的指针时,比如
Foo fp*;
fp has what we call a static type, of pointer-to Foo. If class Bar is a subclass of Foo, and I point fp at new Bar:
fp 有我们所说的静态类型,指向 Foo 的指针。如果类 Bar 是 Foo 的子类,并且我将 fp 指向新的 Bar:
fp = new Bar1();
then we say that the object pointed to by fp has the dynamic type of Bar.
那么我们说fp指向的对象的动态类型是Bar。
if Bar2 also publicly derives from Foo, I can do this:
如果 Bar2 也公开来自 Foo,我可以这样做:
fp = new Bar2();
and without ever even knowing what fp points to, I can call virtual methods declared in Foo, and have the compiler make sure that the method defined in he dynamic type pointed to is what's called.
甚至在不知道 fp 指向什么的情况下,我可以调用在 Foo 中声明的虚拟方法,并让编译器确保动态类型中定义的方法所指的是被调用的方法。
For a template< typename T > struct Baz { void doSomething(); };
为一个 template< typename T > struct Baz { void doSomething(); };
Baz<int>
and Baz<float>
are two entirely different class types, with no relationship.
Baz<int>
并且Baz<float>
是两个完全不同的类类型,没有任何关系。
The only "relationship" is that I can call doSomething() on both, but since the static types have no relationship, if I have a Baz<int> bi*
, I can't point it to a Baz<float>
. Not even with a cast. The compiler has no way to "translate" a call to the Baz doSotheing method into a call to a Baz::doSomething() method. That's because there is no "Baz method", there is no Baz, there are ony Baz<int>s
and Baz<float>s
, and Baz<whatevers>
, but there's no common parent. Baz is not a class, Baz is a template, a set of instructions about how to make a class if and only if we have a T parameter that's bound to an actual type (or to a constant).
唯一的“关系”是我可以在两者上调用 doSomething() ,但由于静态类型没有关系,如果我有 a Baz<int> bi*
,我不能将它指向 a Baz<float>
。甚至没有演员。编译器无法将 Baz doSotheing 方法的调用“翻译”为 Baz::doSomething() 方法的调用。那是因为没有“Baz 方法”,没有 Baz,只有Baz<int>s
and Baz<float>s
, and Baz<whatevers>
,但是没有共同的父级。Baz 不是一个类,Baz 是一个模板,一组关于当且仅当我们有一个绑定到实际类型(或常量)的 T 参数时如何创建类的指令。
Now there is one way I can treat those Baz
es alike: in a template, they present the same interface, and the compiler, if it knows what kind of Baz we're really dealing with, can make a staticcall to that method (or a static access of a member variable).
现在有一种方法可以将这些Baz
es 一视同仁:在模板中,它们呈现相同的接口,并且编译器,如果它知道我们真正处理的是哪种 Baz,则可以对该方法进行静态调用(或成员变量的静态访问)。
But a template is not code, a template is meta-code, the instructions of how to synthesize a class. A "call" in a template is not a call,it's an instruction of how to write the code to make a call.
但是模板不是代码,模板是元代码,是如何合成一个类的指令。模板中的“调用”不是调用,而是关于如何编写调用代码的说明。
So. That was long winded and confusing. Outside of a template definition, there is no relationship between a ParamVector and aParamVector. So your assignment can't work.
所以。那是冗长而令人困惑的。在模板定义之外,ParamVector 和aParamVector 之间没有关系。所以你的任务不能工作。
Well. Almost.
好。几乎。
Actually, with partial application of templates, you can write a template functionwhich gives a "recipe" of how to transform a Paramvector<T>
to a ParamVector<U>
. Notice the T and the U. If you can write code to turn any kind of ParamVector, regardless of actual template parameter into any other kind of ParamVector, you can package that up as a partially applied template, and the compiler will add that function to, for example, ParamVector.
事实上,随着模板的部分应用程序,你可以写一个模板函数,其给出了如何改造一个“处方”Paramvector<T>
的ParamVector<U>
。注意 T 和 U。如果您可以编写代码将任何类型的 ParamVector,无论实际模板参数如何转换为任何其他类型的 ParamVector,您可以将其打包为部分应用的模板,编译器会将该函数添加到例如,ParamVector。
That probably involves making a ParamVector<U>
, and transforming each T in the ParamVector<T>
into a U to put in the ParamVector<U>
. Which still won't let you asign to a ParamConsumer<T>
.
这可能涉及制作 a ParamVector<U>
,并将 中的每个 TParamVector<T>
转换为 U 以放入ParamVector<U>
。这仍然不会让您分配给ParamConsumer<T>
.
So maybe you want to have both templates and inheritance. In that case, you can same that all ParamVectors regardless of type inherit from some non-template class. And then there would be a relationship between ParamVectors, they'd all be sibling subclasses of that base class.
所以也许你想要同时拥有模板和继承。在这种情况下,您可以让所有 ParamVectors 无论类型如何都继承自某个非模板类。然后在 ParamVectors 之间会有关系,它们都是该基类的兄弟子类。
回答by Fabio Ceconello
Notice that when you do an implicit cast, what the compiler can do without your help (I mean, without additional code) is just reference-upcast. That means that, seeing the object as a reference (for cast purposes only, the nature of the object doesn't change of course), it can look at it as one of its ancestors. When you have two template instances, none of them is an ancestor of the other (neither they are necessarily in the same hierarchy). After trying that, the compiler looks for cast operators, constructors, etc. At this stage, probably a temporary object needs to be created, except when you're doing attribution and there's an attribution operator that fits.
请注意,当您进行隐式转换时,编译器可以在没有您帮助的情况下(我的意思是,没有附加代码)所做的只是引用向上转换。这意味着,将对象视为引用(仅出于强制转换的目的,对象的性质当然不会改变),它可以将其视为其祖先之一。当您有两个模板实例时,它们都不是另一个的祖先(它们也不一定在同一层次结构中)。尝试之后,编译器会查找转换运算符、构造函数等。在此阶段,可能需要创建一个临时对象,除非您在进行归因并且有适合的归因运算符。
One solution to your problem would be to use a conversion constructor:
您的问题的一种解决方案是使用转换构造函数:
template<class T> class ParamVector
{
public:
vector <T> gnome;
vector <T> data_params;
ParamVector()
{
}
template <class T2> ParamVector(const ParamVector<T2> &source)
{
gnome.reserve(source.gnome.size());
copy(source.gnome.begin(), source.gnome.end(), gnome.begin());
data_params.reserve(source.data_params.size());
copy(source.data_params.begin(), source.data_params.end(), data_params.begin());
}
};
This would create a temporary object whenever you use an instance of the template and other is required. Not a good solution if you're dealing with large containers, the overhead isn't acceptable. Also, if you pass a template instance to a function that requires not an object but a reference, the compiler won't call the conversion constructor automatically (you have to do an explicit call).
每当您使用模板的实例和其他需要时,这将创建一个临时对象。如果您正在处理大型容器,这不是一个好的解决方案,开销是不可接受的。此外,如果您将模板实例传递给不需要对象而是需要引用的函数,编译器将不会自动调用转换构造函数(您必须进行显式调用)。
回答by Fabio Ceconello
You are lost because you can't do it - the two types are completely different. Whenever you come across the need for a cast in your code, you should examine both your code and your design very closely - one or both is probably wrong.
你迷路了,因为你做不到——这两种类型是完全不同的。每当您发现需要在代码中进行强制转换时,您都应该非常仔细地检查您的代码和您的设计——其中一个或两个都可能是错误的。
回答by Doug T.
You can't do this with a direct cast because double and float are completly different sizes. Doubles are going to be 64 bits while floats are 32. A pointer forced to cast from a
你不能用直接转换来做到这一点,因为 double 和 float 是完全不同的大小。双精度数将是 64 位,而浮点数是 32 位。强制从 a 强制转换的指针
ParamVector<float>
to
到
ParamVector<double>
is going to misinterpret the data and give you garbage. You may want to google "pointer aliasing" or just learn more about pointers in general to see how this isn't going to work.
会误解数据并给你垃圾。您可能想在谷歌上搜索“指针别名”,或者只是了解更多关于一般指针的信息,看看这将如何工作。
Think about it for a second you have one array that is a bunch of 64 bit values with fields layed out like this
考虑一下,你有一个数组,它是一堆 64 位值,字段布局如下
0 => abcdabcd12341234
1 => abcdabcd12341234
If you force this to be interpreted as an array of 32 bit values, its going to not be interpreted correctly. You may or may not get something like
如果您强制将其解释为 32 位值的数组,它将无法正确解释。你可能会也可能不会得到类似的东西
0 => abcdabcd
1 => 12341234
2 => abcdabcd
3 => abcdabcd
or it could be switched so that the 12341234's come first, or something stranger due to how the word ordering works out.
或者它可以切换,以便 12341234 先出现,或者由于单词排序的方式而变得更奇怪。
回答by Matt Cruikshank
You mentioned "template casting" in your headline, so I'll presume that ParamVector
is a templated type. That means that foo
could be templated as well, and that would solve your problem.
您在标题中提到了“模板转换”,所以我假设这ParamVector
是一种模板类型。这意味着foo
也可以模板化,这将解决您的问题。
template <typename T>
void foo(ParamVector<T> const& data)
{
}
回答by John Dibling
You can't cast templates like this because the types are unrelated.
您不能像这样转换模板,因为类型是不相关的。
However, you can add a conversion function, such as:
但是,您可以添加转换函数,例如:
(Your code wasn't really complete, so I can post complete code either. Hopefully you will get the idea.)
(你的代码不是很完整,所以我也可以发布完整的代码。希望你能明白。)
template<class T> class ParamVectorConsumer
{
public:
ParamVector<T> test;
template<T2> ParamVectorConsumer<T2> convert()
{
ParamVectorConsumer<T2> ret;
ret = this->...
}