使用模板类型将参数传递给函数

Passing Arguments to Function using Template Types

本文关键字:参数传递 函数 类型      更新时间:2023-10-16

我正在向IMO挑战C++模板编程的极限。该系统是一个Arduino,但我的尝试适用于任何微控制器系统。

我使用一个带有"int"参数的模板类来定义Pins

template<const int pin>
struct Pin {
    Pin() { mode(pin, 0); }
};
template<const int pin>
class PinOut : public Pin<pin> {};  

我可以创建模板类来使用PinOut,比如:

template<typename F>
class M {
public:
    M() { }
    F mF;
};
M<PinOut<1>> m1;
template<int F>
class N {
public:
    N() { }
    Pin<F> mF;
};
N<1> n1;

但我不想在使用PinOut的类中使用模板。这说明了我的想法显示了可能的方法,但显然不起作用。

class R {
public:
    R(const int i) {
    }
PinOut<i> mF;  // create template instance here
};
R r1(1);  // what I'd like to able to do

我认识到问题是在类R中创建一个类型。

另一种可能性是实例化PinOut变量并将其传入,但再次在类内传递和创建类型是个问题。类似这样的东西:

class S {
public:
    S(PinOut<int>& p) { } // how to pass the type and instance
    PinOut<p>& mF;   // and use it here
};
PinOut<1> pp;
S s1(pp);

如果这听起来很突然,很抱歉,但请不要问我为什么或想做什么。这是一个实验,我正在推动我对C++的理解,尤其是模板。我知道还有其他方法。

是的,任何采用该类型的函数本身都必须是模板。

但是,在不知道T的情况下,Pin的整个家族是否在某种程度上是有意义的?这可以用一个非模板基类来处理。基类的想法特别方便,因为它可以包含do了解T的虚拟函数。这使您可以根据需要在编译时和运行时多态性之间切换。在极端情况下,与Java和.NET.中的"泛型"语法相同,这就成为了一个较弱的想法

更普遍地说,这是一个被称为类型擦除的概念。您可以搜索该术语以了解更多信息。它被设计成库,以保持公共代码的通用性,并防止通过多次实例化对同一段落进行无端的乘法运算。

在您的情况下,pin是一个非类型参数,这是泛型甚至不会做的事情。但它可能根本不会对类型产生太大影响:如果成员根据pin而更改呢?这可能是一个数组绑定,或者是一个用于提供编译时知识和优化的编译时常数,或者只是为了使类型不同。

所有这些情况都是可以在运行时处理的。如果它的唯一目的是使类型不同(例如,让编译器检查您是否将时间值和距离值传递给正确的参数),那么真正的内核是基类中的所有,该基类省略了区别性。

如果是数组绑定或其他类型的差异,可以在运行时进行管理,那么基类或适配器/代理也可以在运行时间进行管理。更一般地说,一个不影响类布局的编译时常数可以在运行时被知道,具有相同的效果,只是较少的优化。

根据您的示例,将pin作为构造函数参数是明智的,类可以通过运行时配置以正常方式实现。为什么它是一个模板?大概是为了在编译时进行检查,将不同的东西分开。这不会导致它们以不同的方式工作,所以您希望编译时部分是可选的。因此,这是一个基类完成任务的情况:

class AnyPin
{
public:
   AnyPin (int pin);  // run-time configuration
};
template <int pin>
class Pin : public AnyPin { ⋯ };

现在,您可以编写采用AnyPin的函数,或者编写采用Pin<5> 并进行编译时检查。

那么pin在布局和功能方面对类做了什么呢?它是否做了任何事情,使得仅仅将其实现为运行时构造函数值是不可接受的?

你要求我们不要询问你想做什么,但我必须说,模板有一定的功能和好处,一定有理由将其作为模板。简单地说,以语言为中心,我是否错过了上述分析?如果我的总结没有涵盖它,你能给出一个C++编程的理由,让它成为一个模板吗?这可能就是为什么到目前为止你还没有得到任何答案的原因。