【问题标题】:Template parameters dilemma模板参数困境
【发布时间】:2010-01-17 13:57:14
【问题描述】:

我有一个难题。假设我有一个模板类:

template <typename ValueT>
class Array
{
public:
    typedef ValueT ValueType;
    ValueType& GetValue()
    {
        ...
    }
};

现在我想定义一个函数,它接收对类的引用并调用函数 GetValue()。我通常考虑以下两种方式:

方法一:

template <typename ValueType>
void DoGetValue(Array<ValueType>& arr)
{
    ValueType value = arr.GetValue();
    ...
}

方法二:

template <typename ArrayType>
void DoGetValue(ArrayType& arr)
{
    typename ArrayType::ValueType value = arr.GetValue();
    ...
}

这两种方法几乎没有区别。即使调用这两个函数看起来也完全一样:

int main()
{
    Array<int> arr;
    DoGetValue(arr);
}

现在,两者中哪一个是最好的?我能想到一些缺点和优点:

方法 1 优点:

参数是一个真正的类而不是模板,因此用户更容易理解界面 - 参数必须是数组是非常明确的。在方法 2 中,您只能从名称中猜测它。我们在函数中使用 ValueType,这样比隐藏在 Array 中并且必须使用作用域运算符访问时更清晰。

此外,typename 关键字可能会让许多不熟悉模板的程序员感到困惑。

方法 2 优点:

这个函数更“真实”地实现了它的目的。当我想如果它,我真的不需要类是数组。我真正需要的是一个具有 GetValue 方法和 ValueType 类型的类。就这样。也就是说,这种方法更通用。

这种方法对 Array 类的变化也较少依赖。如果Array的模板参数改变了怎么办?为什么它会影响 DoGetValue?它并不关心 Array 是如何定义的。

每次我遇到这种情况时,我都不知道该选择什么。你的选择是什么?

【问题讨论】:

  • 为了通用性,我还会考虑“更改”您自己的类的接口并尝试模仿 STL 容器,这样您就可以在 STL 容器上使用自己的函数模板作为奖金 > value_type 而不是 ValueTypefrontback 而不是 GetValue(或者可能是 at,如果它需要一个职位?)等等......
  • @Matthieu,好点子!这是我应该考虑的事情。我从来没有想过STL模仿的可能性。它确实很有用,甚至可以在代码中提供视觉线索。谢谢。

标签: c++ templates


【解决方案1】:

第二个更好。在你的第一个“优点”中,你说,“参数必须是数组是非常明确的”。但是说参数必须是数组是不必要的限制。在第二个示例中,任何具有合适的 GetValue 函数的类都可以。由于这是一个不必要的限制,因此最好将其删除(第二个)而不是使其明确(第一个)。您将编写更灵活的模板,这在您以后想从非数组的东西中获取值时很有用。

【讨论】:

  • 一般来说我同意,我自己倾向于选择第二个选项,但在一个封闭的生态系统中,我实际上想要强制使用 Array,这个限制可以成为一个优势。
  • 是的,可能我应该添加一些模棱两可 - 当我说“更好”时,我的意思是它是首选,除非有一些特定因素,问题中没有说明,这使得某些特定的东西更好案子。例如,如果您使用 Array 的 15 种不同功能,并且您希望 Array 的接口在开发过程中发生很大变化,并且要始终更改 DoGetValue 以匹配,那么让人们将 DoGetValue 与另一个类一起使用意味着他们将不得不不断更改另一个类也是,这可能比让他们使用数组更糟糕。
  • @FireAphis,如果您想限制为 Array(我可以想象,当您重载的是运算符时,减少歧义的机会是一个很好的理由),那么为什么不使用两个中最好的worlds:接受 Array,但仍使用 ::ValueType
【解决方案2】:

如果您的函数非常特定于ArrayType,并且没有其他模板可以满足其接口要求,请使用#1,因为它更短且更具体:临时读者会被告知它在ArrayType 上运行。

如果其他模板有可能与DoGetValue 兼容,请使用#2,因为它更通用。

但着迷是没有用的,因为在它们之间转换很容易。

【讨论】:

  • 我喜欢“无用痴迷”部分:)
【解决方案3】:

我的朋友提出了另外两种更极端的方法:

方法 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();
    ...
}

【讨论】:

  • 方法3需要typename ArrayType::ValueType
  • 为什么要限制参数的数量?这看起来像是在踢自己的脚。
  • @Potatoswatter,你是对的,当然。这些解决方案更多是出于学术兴趣:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-14
  • 1970-01-01
相关资源
最近更新 更多