考虑这段代码:
struct B {};
struct D1 : B {};
struct D2 : B {};
#define get if (s) return d1; else return d2;
volatile bool s;
struct C {
const B& f() const { get }
B& f() { get }
private:
D1 d1;
D2 d2;
};
在这里你可以看到不同的版本f()应该返回相同的对象(在一种情况下是 const,在另一种情况下不是),基于一些选择逻辑,这可能非常复杂。示例中为了避免重复该逻辑的代码,通过#define.
f()是否可以在不借助预处理器服务的情况下避免不同版本中的代码重复?
你可以写类似下面的东西
这是演示程序
其输出到控制台
我想出了一个具有模板友好功能的变体:
或者你甚至可以将它移到一个类中:
并且由于类型
R本质上可以从 中存在常量这一事实推导出来,因此T可以从模板中完全删除该类型:那。调用时无需明确指定类型
g:明显的选择:
例子:
出于稳定性考虑的代码重复问题通常有两种形式:
在单个函数级别:当有两个具有相同实现的函数时,不同之处仅在于输入类型的恒定性(作为一种特殊情况,包括
*this类方法中的恒定性)和相应的返回值的恒定性。在 C 语言中,解决这个问题的一个著名习语是编写一个函数,在尊重输入数据的常量性的框架内解决问题,然后简单地无条件地从返回值中删除常量性(例如,参见标准函数
strstr)。在这种情况下,假设调用代码知道数据恒常性的情况,将在适当的函数调用期间“绅士地”返回常量“丢失”。在C++语言中,这种做法在技术上也是适用的,但不习惯使用。更准确地说,传统的 C++ 惯用语在内部基于几乎相同的方法,在外部实现时略有不同:为函数的常量版本提供了完整的实现,为函数的第二个(非常量)版本提供了同样的功能建立在它之上。后者是通过 const 通过从返回值中删除 constness 来实现的
这种方法非常适合您的情况。
在单个类的级别:代码需要实现两个类,从源代码的角度来看,这两个类实际上是相同的,只是所处理数据的外部稳定性不同。一个很好的例子是容器迭代器类的 const 和非常量版本。
在这种情况下,一种可行的方法是将通用功能实现为用所需类型(在最简单的情况下为一个)参数化的模板类,并通过此模板的特化来实现所需的最终类。就像是
PS您自己使用模板函数的答案实际上是对上述第二种方法对第一种情况的改编。毫无疑问,它会起作用,但在这种情况下,在
const_cast我看来,带有 的平庸选项看起来更简单、更合适。