【发布时间】:2010-08-25 04:39:38
【问题描述】:
给定以下模板:
template <typename T>
class wrapper : public T {};
Foo 类型的对象和wrapper<Foo> 类型的对象在接口或行为上有哪些明显的区别?
我已经知道一个:
-
wrapper<Foo>仅具有空值构造函数、复制构造函数和赋值运算符(仅当这些操作在Foo上有效时才具有)。这种差异可以通过在wrapper<T>中使用一组模板化构造函数来缓解,这些构造函数将值传递给 T 构造函数。
但我不确定可能存在哪些其他可检测的差异,或者是否有隐藏它们的方法。
(编辑)具体示例
有些人似乎在询问这个问题的背景,所以这里是对我的情况的(稍微简化的)解释。
我经常编写具有可调整值的代码,以调整系统的精确性能和操作。我希望有一种简单(低代码开销)的方式来通过配置文件或用户界面公开这些值。我目前正在编写一个库来允许我这样做。预期的设计允许这样使用:
class ComplexDataProcessor {
hotvar<int> epochs;
hotvar<double> learning_rate;
public:
ComplexDataProcessor():
epochs("Epochs", 50),
learning_rate("LearningRate", 0.01)
{}
void process_some_data(const Data& data) {
int n = *epochs;
double alpha = *learning_rate;
for (int i = 0; i < n; ++i) {
// learn some things from the data, with learning rate alpha
}
}
};
void two_learners(const DataSource& source) {
hotobject<ComplexDataProcessor> a("FastLearner");
hotobject<ComplexDataProcessor> b("SlowLearner");
while (source.has_data()) {
a.process_some_data(source.row());
b.process_some_data(source.row());
source.next_row();
}
}
运行时,这将设置或读取以下配置值:
FastLearner.Epochs
FastLearner.LearningRate
SlowLearner.Epochs
SlowLearner.LearningRate
这是由代码组成的(碰巧我的用例甚至不是机器学习),但它显示了设计的几个重要方面。可调整的值都是命名的,并且可以组织成层次结构。值可以通过几种方法进行分组,但在上面的示例中,我只展示了一种方法:将对象包装在 hotobject<T> 类中。在实践中,hotobject<T> 包装器有一个相当简单的工作——它必须将对象/组名称推送到线程本地上下文堆栈,然后允许构造 T 对象(此时 hotvar<T>构造值并检查上下文堆栈以查看它们应该在哪个组中),然后弹出上下文堆栈。
按如下方式完成:
struct hotobject_stack_helper {
hotobject_stack_helper(const char* name) {
// push onto the thread-local context stack
}
};
template <typename T>
struct hotobject : private hotobject_stack_helper, public T {
hotobject(const char* name):
hotobject_stack_helper(name) {
// pop from the context stack
}
};
据我所知,这个场景中的构造顺序非常明确:
-
构造
hotobject_stack_helper(将名称推入上下文堆栈) -
T被构造——包括构造T的每个成员(热变量) -
hotobject<T>构造函数的主体运行,弹出上下文堆栈。
所以,我有工作代码来执行此操作。然而,还有一个问题,那就是:通过使用这种结构,我可能会给自己带来什么问题。这个问题很大程度上归结为我实际要问的问题:hotobject 的行为与 T 本身有何不同?
【问题讨论】:
-
所以,您正在尝试制作一个完全不执行任何操作的包装模板...可能有人问为什么?
-
只有当类中有公共方法时才存在“可见”行为。
-
真正的包装器模板确实有行为(虽然没有额外的成员),当然,但这种额外行为的效果是显而易见的。该问题旨在隔离最小情况下存在的差异(这是一个什么都不做的包装类)。
-
我应该指出,很明显,我永远无法完全隐藏
hotobject<T>和T之间的区别。但是,一些差异可能是可以接受的(因为我可以轻松解决它们,或者因为它们根本不会出现在我的特定用例中),而其他差异可能代表一个显示停止问题,这意味着我必须重新设计库才能使用不同的结构。