C++编译时多态性
C++ Compile-time polymorphism
有两个不相关的结构A和B
template <typename T>
struct A {};
template <typename T>
struct B {};
一个枚举类型
typedef enum { ma, mb} M;
和C类包含功能模板
class C
{
public:
template <typename T>
static void f1 ( A <T> &a) {}
template <typename T>
static void f2 ( B <T> &b) {}
template <typename U>
static void algo (U &u, M m)
{
/*Long algorithm here
....
*/
if ( m == ma) f1(u);
else f2(u);
}
};
静态方法算法包含一些算法,这是相当困难的。。。它将一些值和结果修改为结构A或B。
我想根据M值用对象A或B运行静态方法algo。但是如何对我的编译器说:-)
int main()
{
A <double> a;
C::algo (a, ma); //Error
}
Error 1 error C2784: 'void C::f1(A<T>)' : could not deduce template argument for 'A<T>' from 'B<T>
A] 我考虑的是指向函数的指针,但它们不适用于函数模板。
B] 也许编译多态性可以帮助
template <typename U, M m>
static void algo (U &u, M <m> ) { ...} //Common for ma
template <typename U, M m>
static void algo (U &u, M <mb> ) { ...} //Spec. for mb
但这个解决方案有一个大问题:两个实现都应该不必要地包含几乎相同的代码(为什么要写两次算法?)。
因此,我需要一个函数algor()来处理两种类型的参数A和B。有更舒适的解决方案吗?
您似乎在使用枚举来传递用户的类型信息。我建议你不要这样做。
在最简单的情况下,如果f1
和f2
被重命名为f
,那么你可以完全删除if
并只调用它。编译器会为你调用适当的重载。
如果您不能或不想重命名函数模板,那么您可以编写一个助手模板来为您分派(未定义基类模板,分派到适当静态函数的A
和B
的专业化)
如果枚举用于其他内容(编译器无法为您解析),您仍然可以传递它并重写要在枚举上调度的帮助程序,而不是参数的类型,并且您必须重写代码以使枚举值作为编译时常数(最简单的方法是:将其作为模板参数传递给algo
)。在这种情况下,如果你愿意,你可以写函数专业而不是类,因为它们将是完整的专业。但请注意,如果您可以避免传递它,您将删除一系列错误:传递错误的枚举值。
// Remove the enum and rename the functions to be overloads:
//
struct C { // If everything is static, you might want to consider using a
// namespace rather than a class to bind the functions together...
// it will make life easier
template <typename T>
static void f( A<T> & ) { /* implement A version */ }
template <typename T>
static void f( B<T> & ) { /* implement B version */ }
template <typename T> // This T is either A<U> or B<U> for a given type U
static void algo( T & arg ) {
// common code
f( arg ); // compiler will pick up the appropriate template from above
}
};
对于其他替代方案,如果封闭范围是一个命名空间,则会更容易,但想法是一样的(只是可能需要更难地对抗语法:
template <typename T>
struct dispatcher;
template <typename T>
struct dispatcher< A<T> > {
static void f( A<T>& arg ) {
C::f1( arg );
}
};
template <typename T>
struct dispatcher< B<T> > {
static void f( B<T>& arg ) {
C::f2( arg );
}
};
template <typename T>
void C::algo( T & arg ) {
// common code
dispatcher<T>::f( arg );
}
同样,让它与一个类一起工作可能有点棘手,因为它可能需要几个正向声明,而且我手头没有编译器,但草图应该会引导你朝着正确的方向前进。
正常函数重载就足够了:
template <typename T>
static void f1 ( A <T> &a) {}
template <typename T>
static void f2 ( B <T> &b) {}
template <typename T>
static void algo (A<T>& u) {
f1(u);
}
template <typename T>
static void algo (B<T>& u) {
f2(u);
}
然后:
A<int> a;
Foo::algo(a);
尽管目前还不清楚你会从这样的安排中得到什么。
如果你真的需要在一个函数中做到这一点,你可以使用typetraits:
template<typename T, T Val>
struct value_type { static const T Value = Val; };
struct true_type : public value_type<bool, true>{};
struct false_type : public value_type<bool, false>{};
template<class T>
struct isClassA : public false_type{};
template<>
struct isClassA<A> : public true_type{};
template < typename T >
void Algo( T& rcT )
{
if ( true == isClassA<T>::Value )
{
// Class A algorithm
}
else
{
// Other algorithm
}
};
m
参数的值在运行时之前是未知的,因此编译器在专门化函数时必须为if (m == ma)
和else
分支生成代码。然后它会抱怨,因为它不明白如果你碰巧打电话给C::algo(a,mb)
或类似的人,他应该怎么做。
正如Jon所建议的,重载应该可以修复您的情况,请尝试使用以下代码:
template<typename U>
static void f12(A<U>&u) { f1(u); }
template<typename U>
static void f12(B<U>&u) { f2(u); }
template<typename U>
static void algo(U& u, M m)
{
/* long algorithm here
...
*/
//use overloading to switch over U type instead of M value
f12(u);
}
此外,只要指定模板参数,就可以将函数指针与模板函数一起使用:
template<typename U>
static void algo(U& u, M m, void(*)(U&) func)
{
/* ... */
(*func)(u);
}
int main()
{
A <double> a;
C::algo (a, ma, &C::f1<double> );
}
- 多态性和功能结合
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- C ++中的方法覆盖:是编译时还是运行时多态性?
- 运行时与编译时多态性:更好的可读性与编译时错误检查,更重要的是
- 使用数组对对象的编译时多态性是否可行?
- 如果在编译时间中创建虚拟表,那么为什么我们将其称为运行时间多态性
- 编译时多态性运行时多态性是这样的吗
- C++编译时模板多态性
- 使用枚举编译时多态性
- 避免编译时已知类型的模板冗长和动态多态性
- 为什么不能在编译时解决运行时多态性?
- 如何实现几个函数的编译时多态性
- 尝试使用多态性C++时发生编译错误
- C++编译时多态性
- 编译时与运行时多态性在c++中的优缺点
- 允许运行时和编译时多态性的灵活方式
- 数据成员的编译时多态性
- 编译时多态性解决方案
- CRTP和动态多态性编译错误
- c++中运行时和编译时多态性的区别