April 21th Tuesday (四月 二十一日 火曜日)

本文探讨了C++中模板参数的使用方式,并通过实例详细解释了如何利用模板参数创建通用类。此外,还讨论了引用参数的应用场景,特别是当实际参数不匹配时,C++如何生成临时变量来处理这一情况。

 Templates As Parameters

// tempparm.cpp -- template template parameters
#include <iostream>
using namespace std;
#include "stacktp.h"

template <template <typename T> class Thing>
class Crab
{
private:
    Thing<int> s1;
    Thing<double> s2;
public:
    Crab() {};
    // assumes the thing class has push() and pop() members
    bool push(int a, double x) { return s1.push(a) && s2.push(x); }
    bool pop(int & a, double & x){ return s1.pop(a) && s2.pop(x); }
};

int main()
{
    Crab<Stack> nebula;
// Stack must match template <typename T> class thing
    int ni;
    double nb;

    while (cin>> ni >> nb && ni > 0 && nb > 0)
    {
        if (!nebula.push(ni, nb))
            break;
    }

    while (nebula.pop(ni, nb))
           cout << ni << ", " << nb << endl;
    cout << "Done./n";

    return 0;
}

  The Thing<int> is instantiated as Stack<int> and Thing<double> is instantiated as Stack<double>. In short,
the template parameter Thing is replaced by whatever template type is used as a template argument in declaring
a Crab object.

Temporary Variables, Reference Arguments, and const

  C++ can generate a temporary variable if the actual argument doesn't match a reference argument. Currently,
C++ permits this only if the argument is a const reference, but this is a new restriction. Let's look at the cases
in which C++ does generate temporary variables and see why the restriction to a const reference makes sense.

  First, when is a temporary variable created? Provided that the reference parameter is a const, the compiler
generates a temporary variable in two kinds of situations:

* The actual argument is the correct type, but isn't an Lvalue
* The actual argument is of the wrong type, but of a type that can be converted to the correct type

void swapr(int & a, int & b)  // use references
{
    int temp;

    temp = a;      // use a, b for values of variables
    a = b;
    b = temp;
}

double refcube(const double &ra)
{
     return ra * ra * ra;
}

Now consider the following code:

double side = 3.0;
double * pd = &side;
double & rd = side;
long edge = 5L;
double lens[4] = { 2.0, 5.0, 10.0, 12.0} ;
double c1 = refcube(side);          // ra is side
double c2 = refcube(lens[2]);       // ra is lens[2]
double c3 = refcube(rd);            // ra is rd is side
double c4 = refcube(*pd);           // ra is *pd is side
double c5 = refcube(edge);          // ra is temporary variable
double c6 = refcube(7.0);           // ra is temporary variable
double c7 = refcube(side + 10.0);   // ra is temporary variable

  The arguments side, lens[2], rd, and *pd are type double data objects with names, so it is possible to
generate a reference for them, and no temporary variables are needed. (Recall that an element of an array
behaves like a variable of the same type as the element.) But edge, although a variable, is of the wrong type.
A reference to a double can't refer to a long. The arguments 7.0 and side + 10.0, on the other hand, are
the right type, but are not named data objects. In each of these cases, the compiler generates a temporary,
anonymous variable and makes ra refer to it. These temporary variables last for the duration of the function
call, but then the compiler is free to dump them.

  What would happen if we did the following under the freer rules of early C++?

long a = 3, b = 5;
swapr(a, b);

  Here there is a type mismatch, so the compiler would create two temporary int variables, initialize them to 3 and 5,
and then swap the contents of the temporary variables, leaving a and b unaltered.

  In short, if the intent of a function with reference arguments is to modify variables passed as arguments, situations
that create temporary variables thwart that purpose. The solution is to prohibit creating temporary variables in these
situations, and that is what the C++ standard now does. (However, some compilers still, by default, issue warnings
instead of error messages, so if you do see a warning about temporary variables, don't ignore it.)

  Now think about the refcube() function. Its intent is merely to use passed values, not to modify them, so temporary
variables cause no harm and make the function more general in the sorts of arguments that it can handle. Therefore, if
the declaration states that a reference is const, C++ generates temporary variables when necessary. In essence, a C++
function with a const reference formal argument and a nonmatching actual argument mimics the traditional passing by value
behavior, guaranteeing that the original data is unaltered and using a temporary variable to hold the value.

Remember

  If a function call argument isn't an Lvalue or does not match the type of the corresponding const reference parameter,
C++ creates an anonymous variable of the correct type, assigns the value of the function call argument to the anonymous
variable, and has the parameter refer to that variable.

Use const When You Can

  There are three strong reasons to declare reference arguments as references to constant data:

  * Using const protects you against programming errors that inadvertently alter data.
  * Using const allows a function to process both const and non-const actual arguments, while a function omitting const in
   the prototype only can accept non-const data.
  * Using a const reference allows the function to generate and use a temporary variable appropriately.

  You should declare formal reference arguments as const whenever it's appropriate to do so.

  Typically, the reference refers to a reference passed to the function in the first place, so the calling function actually
winds up directly accessing one of its own variables.

Remember

  A function that returns a reference is actually an alias for the referred-to variable.

  You can assign a value (including a structure or a class object) to a C++ function only if the function returns a reference
to a variable or, more generally, to a data object. In that case, the value is assigned to the referred-to variable or data object.

  There are two main reasons for using reference arguments:

  * To allow you to alter a data object in the calling function
  * To speed up a program by passing a reference instead of an entire data object

  The second reason is most important for larger data objects, such as structures and class objects.

下载方式:https://pan.quark.cn/s/a4b39357ea24 布线问题(分支限界算法)是计算机科学和电子工程领域中一个广为人知的议题,它主要探讨如何在印刷电路板上定位两个节点间最短的连接路径。 在这一议题中,电路板被构建为一个包含 n×m 个方格的矩阵,每个方格能够被界定为可通行或不可通行,其核心任务是定位从初始点到最终点的最短路径。 分支限界算法是处理布线问题的一种常用策略。 该算法与回溯法有相似之处,但存在差异,分支限界法仅需获取满足约束条件的一个最优路径,并按照广度优先或最小成本优先的原则来探索解空间树。 树 T 被构建为子集树或排列树,在探索过程中,每个节点仅被赋予一次成为扩展节点的机会,且会一次性生成其全部子节点。 针对布线问题的解决,队列式分支限界法可以被采用。 从起始位置 a 出发,将其设定为首个扩展节点,并将与该扩展节点相邻且可通行的方格加入至活跃节点队列中,将这些方格标记为 1,即从起始方格 a 到这些方格的距离为 1。 随后,从活跃节点队列中提取队首节点作为下一个扩展节点,并将与当前扩展节点相邻且未标记的方格标记为 2,随后将这些方格存入活跃节点队列。 这一过程将持续进行,直至算法探测到目标方格 b 或活跃节点队列为空。 在实现上述算法时,必须定义一个类 Position 来表征电路板上方格的位置,其成员 row 和 col 分别指示方格所在的行和列。 在方格位置上,布线能够沿右、下、左、上四个方向展开。 这四个方向的移动分别被记为 0、1、2、3。 下述表格中,offset[i].row 和 offset[i].col(i=0,1,2,3)分别提供了沿这四个方向前进 1 步相对于当前方格的相对位移。 在 Java 编程语言中,可以使用二维数组...
源码来自:https://pan.quark.cn/s/a4b39357ea24 在VC++开发过程中,对话框(CDialog)作为典型的用户界面组件,承担着与用户进行信息交互的重要角色。 在VS2008SP1的开发环境中,常常需要满足为对话框配置个性化背景图片的需求,以此来优化用户的操作体验。 本案例将系统性地阐述在CDialog框架下如何达成这一功能。 首先,需要在资源设计工具中构建一个新的对话框资源。 具体操作是在Visual Studio平台中,进入资源视图(Resource View)界面,定位到对话框(Dialog)分支,通过右键选择“插入对话框”(Insert Dialog)选项。 完成对话框内控件的布局设计后,对对话框资源进行保存。 随后,将着手进行背景图片的载入工作。 通常有两种主要的技术路径:1. **运用位图控件(CStatic)**:在对话框界面中嵌入一个CStatic控件,并将其属性设置为BST_OWNERDRAW,从而具备自主控制绘制过程的权限。 在对话框的类定义中,需要重写OnPaint()函数,负责调用图片资源并借助CDC对象将其渲染到对话框表面。 此外,必须合理处理WM_CTLCOLORSTATIC消息,确保背景图片的展示不会受到其他界面元素的干扰。 ```cppvoid CMyDialog::OnPaint(){ CPaintDC dc(this); // 生成设备上下文对象 CBitmap bitmap; bitmap.LoadBitmap(IDC_BITMAP_BACKGROUND); // 获取背景图片资源 CDC memDC; memDC.CreateCompatibleDC(&dc); CBitmap* pOldBitmap = m...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值