我今天有更多有趣的恶作剧。
我对C ++中的模板有些陌生。这里是一些当前在我的代码中的类:
class location2d
{
int x, y;
}
class location3d
{
int x, y, z;
}
template <typename T>
class myClass : public parentClass<float, T>
{
private:
virtual void myFunction (T position) const override final
{
// some math stuff (this part doesn't matter)
something = position.x + position.y;
}
int something;
};
现在,这已硬编码到location2d。如果location3d传入,我需要myFunction()具有不同的行为。例如:
virtual void myFunction (T position) const override final
{
something = position.x + position.y + position.z;
}
我已经阅读了模板专业化知识,但是由于myFunction()覆盖了基类中的虚函数,所以这变得棘手。据我了解,我们无法专门研究虚拟功能。无论如何我都尝试过。它讨厌它。
我的第二个想法是键入检查模板,然后仅调用单独的帮助器:
virtual void myFunction (T position) const override final
{
if (std::is_same<T, location3d) {myFunction3(position);}
else {myFunction2(position);}
}
void myFunction2 (T position) const
{
something = position.x + position.y;
}
void myFunction3 (T position) const
{
something = position.x + position.y + position.z;
}
这里的问题是编译器抛出“ location2d不包含成员'z'”,这是绝对正确的。但是,除非存在z,否则不会调用myFunction3()。
接下来,我尝试专门进行强制转换,以使T不再是模棱两可的:
virtual void myFunction (T position) const override final
{
if (std::is_same<T, location3d>::value) {myFunction3((location3d)position);}
else {myFunction2((location2d)position);}
}
““类型转换”:无法从“ T”转换为“ location3””。
最终想法:由于辅助函数不是虚拟的,也许我可以专门介绍这两个函数。
virtual void myFunction (T position) const override final
{
if (std::is_same<T, location3d>::value) {mySecondFunction<location3d>(position);}
else {mySecondFunction<location2d>(position);}
}
template<>
void mySecondFunction<location2d> (location2d position) const {}
template<>
void mySecondFunction<location3d> (location3d position) const {}
我不确定我是否做错了,但是它引发了很多语法错误,这些错误我不知道如何解决。
归根结底,我想做的就是让myFunction()的行为根据是否存在'z'进行更改,并且我不喜欢它的完成方式。我觉得我这里一定缺少一些简单的东西。
您进行类型检查的想法是正确的,但是您的方法需要更多的工作来帮助编译器。
如果您使用的是C ++ 17或更高版本,请if constexpr
与结合使用std::is_same_v
,例如:
template <typename T>
class myClass : public parentClass<float, T>
{
private:
virtual void myFunction (T position) const override final
{
if constexpr (std::is_same_v<T, location3d>) {
something = position.x + position.y + position.z;
}
else {
something = position.x + position.y;
}
}
int something;
};
编译器将if constexpr
在编译时进行完全评估,并消除最终运行时代码中未使用的分支,从而为的每个实例生成不同的代码myClass<T>
,例如:
class myClass<location2d> : public parentClass<float, location2d>
{
private:
virtual void myFunction (location2d position) const override final
{
something = position.x + position.y;
}
int something;
};
class myClass<location3d> : public parentClass<float, location3d>
{
private:
virtual void myFunction (location3d position) const override final
{
something = position.x + position.y + position.z;
}
int something;
};
如果不适合使用C ++ 17或更高版本,则可以reinterpret_cast
改用,例如:
template <typename T>
class myClass : public parentClass<float, T>
{
private:
virtual void myFunction (T position) const override final
{
if (std::is_same<T, location3d>::value) {
// if T is NOT location3d then accessing position.z as-is
// will fail to compile if T::z is missing, hence the cast.
// Since this branch is executed only when T is location3d,
// the cast in this branch is redundant but harmless. But
// this branch is still compiled even when T is NOT loction3d...
something = position.x + position.y + reinterpret_cast<location3d&>(position).z;
}
else {
// no cast is needed here since location2d and location3d
// both have x and y fields...
something = position.x + position.y;
}
}
int something;
};
没有强制转换,编译器将为的每个实例生成如下代码myClass<T>
:
class myClass<location2d> : public parentClass<float, location2d>
{
private:
virtual void myFunction (location2d position) const override final
{
if (false) {
something = position.x + position.y + position.z; // ERROR! location2d::z does not exist...
}
else {
something = position.x + position.y; // OK
}
}
int something;
};
class myClass<location3d> : public parentClass<float, location3d>
{
private:
virtual void myFunction (location3d position) const override final
{
if (true) {
something = position.x + position.y + position.z; // OK
}
else {
something = position.x + position.y; // OK
}
}
int something;
};
当传递position
给非模板成员方法时,会发生相同的问题,例如:
template <typename T>
class myClass : public parentClass<float, T>
{
private:
virtual void myFunction (T position) const override final
{
if (std::is_same<T, location3d) {
// if T is NOT location3d, passing position as-is to myFunction3()
// would fail to compile, hence the cast. Since this branch is
// executed only when T is location3d, the cast in this branch
// is redundant but harmless. But this branch is still compiled
// even when T is NOT loction3d...
myFunction3(reinterpret_cast<location3d&>(position));
}
else {
// if T is NOT location2d, passing position as-is to myFunction2()
// would fail to compile, hence the cast. Since this branch is
// executed only when T is location2d, the cast in this branch
// is redundant but harmless. But this branch is still compiled
// even when T is NOT location2d...
myFunction2(reinterpret_cast<location2d>(position));
}
}
void myFunction2 (location2d position)
{
something = position.x + position.y;
}
void myFunction3 (location3d position)
{
something = position.x + position.y + position.z;
}
int something;
};
没有强制转换,编译器将为的每个实例生成如下代码myClass<T>
:
class myClass<location2d> : public parentClass<float, location2d>
{
private:
virtual void myFunction (location2d position) const override final
{
if (false) {
myFunction3(position); // ERROR! can't convert from location2d to location3d
}
else {
myFunction2(position); // OK
}
}
void myFunction2 (location2d position)
{
something = position.x + position.y;
}
void myFunction3 (location3d position)
{
something = position.x + position.y + position.z;
}
int something;
};
class myClass<location3d> : public parentClass<float, location3d>
{
private:
virtual void myFunction (location3d position) const override final
{
if (true) {
myFunction3(position); // OK
}
else {
myFunction2(position); // ERROR! can't convert from location3d to location2d
}
}
void myFunction2 (location2d position)
{
something = position.x + position.y;
}
void myFunction3 (location3d position)
{
something = position.x + position.y + position.z;
}
int something;
};
话虽这么说,另一种选择是使用模板专业化,那么根本就不需要时髦的转换,例如:
template<typename T>
int add_them_up(T) { return 0; }
template<>
int add_them_up<location2d>(location2d position)
{
return position.x + position.y;
}
template<>
int add_them_up<location3d>(location3d position)
{
return position.x + position.y + position.z;
}
template <typename T>
class myClass : public parentClass<float, T>
{
private:
virtual void myFunction (T position) const override final
{
something = add_them_up<T>(position);
}
int something;
};
编译器将为的每个实例生成如下代码myClass<T>
:
int add_them_up<location2d>(location2d position)
{
return position.x + position.y;
}
int add_them_up<location3d>(location3d position)
{
return position.x + position.y + position.z;
}
class myClass<location2d> : public parentClass<float, location2d>
{
private:
virtual void myFunction (location2d position) const override final
{
something = add_them_up<location2d>(position);
}
int something;
};
class myClass<location3d> : public parentClass<float, location3d>
{
private:
virtual void myFunction (location3d position) const override final
{
something = add_them_up<location3d>(position);
}
int something;
};
在编译器内联调用站点的专用功能后,它们看起来非常熟悉 1
1:<咳嗽> C ++ 17if constexpr
输出!
class myClass<location2d> : public parentClass<float, location2d>
{
private:
virtual void myFunction (location2d position) const override final
{
something = position.x + position.y;
}
int something;
};
class myClass<location3d> : public parentClass<float, location3d>
{
private:
virtual void myFunction (location3d position) const override final
{
something = position.x + position.y + position.z;
}
int something;
};
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句