我陷入两难境地。假设我有一个模板类:
template <typename ValueT>
class Array
{
public:
typedef ValueT ValueType;
ValueType& GetValue()
{
...
}
};
现在我想定义一个接收对类的引用并调用函数GetValue()的函数。我通常会考虑以下两种方式:
方法1:
template <typename ValueType>
void DoGetValue(Array<ValueType>& arr)
{
ValueType value = arr.GetValue();
...
}
方法2:
template <typename ArrayType>
void DoGetValue(ArrayType& arr)
{
typename ArrayType::ValueType value = arr.GetValue();
...
}
这两种方法几乎没有区别。即使调用这两个函数也看起来完全一样:
int main()
{
Array<int> arr;
DoGetValue(arr);
}
现在,哪两个是最好的?我可以想到一些缺点和优点:
方法1专业人士:
参数是一个真正的类而不是模板,因此用户更容易理解界面 - 参数必须是Array非常明确。在方法2中,您只能从名称中猜出它。我们在函数中使用ValueType,因此它比在Array中隐藏时更清晰,并且必须使用范围运算符进行访问。
此外,对于许多非模板精明的程序员来说,typename关键字可能会让人感到困惑。
方法2专业人士:
此功能更符合其目的。当我想到它的时候,我真的不需要这个类是Array。我真正需要的是一个具有方法GetValue和类型ValueType的类。就这样。也就是说,这种方法更通用。
此方法也较少依赖于Array类中的更改。如果更改了Array的模板参数怎么办?为什么它会影响DoGetValue?它并不关心如何定义Array。
答案 0 :(得分:4)
第二个更好。在你的第一个“专业人士”中,你说,“非常明确的是参数必须是数组”。但是说参数必须是一个数组是一个不必要的限制。在第二个示例中,任何具有合适GetValue函数的类都可以。由于这是一个不必要的限制,最好将其删除(第二个)而不是将其删除(第一个)。您将编写更灵活的模板,这在将来想要从不是数组的内容中获取值时非常有用。
答案 1 :(得分:1)
如果您的函数非常特定于ArrayType
,并且没有其他模板可以满足其接口要求,请使用#1,因为它更短且更具体:随意读者被告知它在{{1 }}
如果其他模板可能与ArrayType
兼容,请使用#2,因为它更通用。
但没有任何用处,因为它们很容易在它们之间进行转换。
答案 2 :(得分:0)
我的朋友提出了两种更极端的方法:
方法3:使您能够使用没有:: ValueType的类型。
template <typename ArrayType, typename ValueType = ArrayType::ValueType>
void DoGetValue(ArrayType& arr)
{
ValueType value = arr.GetValue();
...
}
方法4:强制数组成为具有一个模板参数的类的一种很酷的方法。
template <template <typename> class ArrayType, typename ValueType>
void DoGetValue(ArrayType<ValueType>& arr)
{
ValueType value = arr.GetValue();
...
}