有两个不相关的结构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.
我想使用对象A或B运行静态方法算法,具体取决于M值。但是如何对我的编译器说: - )
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
但是这个解决方案有一个大问题:两个实现都应该不必要地包含几乎相同的代码(为什么要编写两次算法?)。
所以我需要一个函数 algo()处理两种类型的参数A和B.是否有更舒适的解决方案?
答案 0 :(得分:3)
您似乎正在使用枚举来传达用户的类型信息。我建议你不要。
在最简单的情况下,如果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 );
}
同样,让它与一个类一起使用可能有点棘手,因为它可能需要一些前向声明,而且我手头没有编译器,但草图应该引导你朝着正确的方向前进。
答案 1 :(得分:2)
正常函数重载就足够了:
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);
虽然目前尚不清楚从这样的安排中获得什么。
答案 2 :(得分:0)
如果你真的需要在一个函数中执行此操作,可以使用type_traits:
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
}
};
答案 3 :(得分:0)
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> );
}