模板是
static polymorphism的高级技术.在类似C的类型语言中,如果没有静态多态,则必须单独定义所使用的每个实体并精确指示所引用的每个实体.
C中静态多态的机制允许自动指示函数或方法,并将其推迟到通过重载构建.它允许您通过模板定义多个共享某些特征的实体,并将特定特化的定义推迟到构建,从使用中推断出来.
(请注意,在各种情况下,静态多态允许单独的代码,因此使用和定义的更改是独立的,这非常有用.)
这种机制的重要含义是模板的每个特化都可能是不同类型的.目前还不清楚,当我在回复时,您是否要在一种类型的容器中存储指向单个或多个类型的特化的指针.可能性还取决于函数模板的参数和结果类型.
C中的函数具有一种类型,该类型是其参数类型列表及其返回类型的组合.换句话说,获取和返回相同类型的两个函数具有相同的类型.如果你的函数模板既没有采用或返回模板参数类型(即.T)也没有模板类型(例如std :: vector< T>),那么这个函数模板的每个特化都将采用并返回相同的类型,因此将是相同类型的功能.
template
int func() { ... }
这个(可以说是无用的)函数模板不带参数并返回int,无论T用于专门化模板.因此,只要将参数定义为int(* f)(),就可以使用指向它的指针.在这种情况下,您可以将指针保持在一个向量中的任何特化.
typedef std::vector<:string> string_vt;
typedef int func_t();
typedef func_t* funcPointer;
typedef std::vector funcPointer_vt;
funcPointer x = &func;
funcPointer y = &func;
可以看出,函数模板的每个特化都是相同的类型,并且两个指针都适合同一个容器.
下一种情况 – 如果函数头取决于模板参数怎么办?每个专业化都会有不同的签名,即不同的函数类型.指向所有这些指针的指针将是不同的类型 – 所以甚至不能将此指针一次性地设置为def.
template
void func(std::vector param) { ... }
在这种情况下,函数模板特化取决于用于专门化的T,具有不同的类型.
typedef int func_t_int(std::vector);
typedef func_t_int* funcPointerInt;
typedef std::vector funcPointerInt_vt;
typedef float func_t_float(std::vector);
typedef func_t_float* funcPointerFloat;
typedef std::vector funcPointerFloat_vt;
funcPointerInt x = &func;
funcPointerFloat x = &func;
专业化有不同的类型,因为它们采用不同类型的向量.指针不适合放在同一个容器中.
值得一提的是,在这种情况下,没有必要单独定义每个指针类型.它们可以是模板类型:
template
using funcPointer = void (*)(std::vector);
现在允许funcPointer< int>用作类型限定符,代替早期的funcPointerInt.
funcPointer y = &func;
在更复杂的情况下,可以创建一个模板,其每个特化都是不同的类型,然后使用具体向量的单个实例来存储指向模板的一个特化类型的函数的各种指针.虽然示例中的简单模板只能为每个类型生成一个函数,但由于每个特化都会产生一种类型的函数和一种类型的函数,因此不可能设想获得各种函数指针的场景,这两种函数都是专门化的.和通常的功能,可能来自各种来源.所以这项技术可能很有用.
但另一种情况是,尽管模板的每个特化都是不同类型的,但是需要在单个std :: vector中存储指向各种特化的指针.在这种情况下,动态多态将有所帮助.为了存储不同类型的值,fe.在一种类型的变量中,指向不同类型函数的指针需要继承.可以将任何子类存储在定义为超类的字段中.但请注意,这不太可能完成任何事情,也可能不是你真正想要的.
我现在看到两种普遍的可能性.使用带有方法的类模板,该方法继承自非模板类.
template
class MyClass : BaseClass
{
public:
T operator()(const T& param,int value);
}
MyClass a;
MyClass b;
BaseClass* ptr = &a;
ptr = &b;
虽然这个类的每个特化都可以是不同的类型,但它们都共享超类BaseClass,所以指向BaseClass的指针实际上可以指向它们中的任何一个,并且std :: vector< funcPointerBase>可以用来存储它们.通过重载operator(),我们创建了一个模仿函数的对象.这样一个类的有趣属性是它可以使用参数构造函数创建多个实例.因此,有效的类模板产生多种类型的特化,反过来,每个专用类都可以生成不同参数化的实例.
template
class MyClass : BaseClass
{
int functor_param;
public:
MyClass(int functor_param);
T operator()(const T& param,int value);
}
此版本允许创建不同的实例:
MyClass a(1);
MyClass b(2);
MyClass c(4);
MyClass* ptr = &a;
ptr = &b;
ptr = &c;
我不是运算符的专家,只是想提出一般的想法.如果它看起来很有趣,我建议现在进行研究.
但从技术上讲,我们不存储函数指针,只是常规对象指针.好吧,如前所述,我们需要继承来使用一种类型的变量来存储各种类型的值.因此,如果我们不使用继承来交换我们的程序函数来实现动态多态,那么我们必须对指针做同样的事情.
template
T func(std::pair < T,char>) {}
template
using funcPointer = T(*)(std::pair);
template
class MyPointer : BasePointer
{
funcPointer ptr;
public:
MyPointer(funcPointer ptr);
T()(std::pair ) operator*(std::pair pair)
{
*ptr(pair);
}
};
这再次允许创建单个std :: vector< BasePointer>存储所有可能的伪函数指针.
现在非常重要的一点.在两种情况下,你会如何调用它们?由于在两种情况下它们都存储在单个std :: vector<>中,因此将它们视为基本类型.特定函数调用需要特定类型的参数并返回特定类型.如果所有子类都可以以相同的方式执行任何操作,则可以通过在基类中定义这样的方法(在任一场景中使用仿函数或指针……)来公开它,但是特定的专用函数调用不是那种事情在所有这些困难之后,您最终想要执行的每个函数调用都是不同的类型,需要不同类型的参数和/或返回不同类型的值.因此,他们可能永远不会在通常的情况下适合相同的位置,而不是模板化的代码,执行中的相同情况.如果他们这样做,那么首先不需要动态多态来解决这个问题.
可以做的一件事 – 非常不鼓励并且可能违背动态多态的目的 – 是在运行时检测子类类型并相应地继续.研究一下,如果你确信你有一个很好的案例来使用它.但最有可能的是,它可能是一个很大的反模式.
但从技术上讲,你可能想做的任何事情都有可能.