C++ 编译时多态性

标签 c++ templates polymorphism static-methods

有两个不相关的结构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);
    }
};

static method algo 包含了一些算法,比较难...它修改了一些值和结果到结构A或B。

我想根据 M 值对对象 A 或 B 运行静态方法算法。但是如何对我的编译器说:-)

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。有没有更舒适的解决方案?

最佳答案

您似乎在使用枚举来传达来自用户的类型信息。我建议你不要。

在最简单的情况下,如果 f1f2 重命名为 f,那么您可以一起删除 if并调用它。编译器将为您调用适当的重载。

如果你不能或不想重命名函数模板,那么你可以编写一个帮助模板来为你分派(dispatch)(基本类模板未定义,AB 的特化 分配给适当的静态函数)

如果枚举用于其他用途(编译器无法为您解决),您仍然可以传递它并重写帮助程序以分派(dispatch)枚举而不是参数类型,您将不得不重写将枚举值作为编译时常量的代码(最简单:将其作为模板参数传递给 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 );
}

同样,让它与一个类一起工作可能有点棘手,因为它可能需要一些前向声明,而且我手头没有编译器,但草图应该会引导你朝着正确的方向前进。

关于C++ 编译时多态性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8961903/

相关文章:

c++ - 为什么 += 对没有值的 std::map 键起作用?

c++ - Visual Studio 中的调用约定

c++ - c++中非void return函数模板的显式方法

javascript - asp.net 中继器在 javascript 中使用模板

c++ - 数据类型 inst 转换正确吗?

c++ - 基类指针,基于派生类型调用方法

c++ - 需要帮助解决使用模板的运行时多态性

c++ - 使用 size_t 声明最大数组

c++ - 创建一个编译时字符串重复一个字符 n 次

Java 脚本 (JSR223) = 用于模板化的 Bean/Script Shell?