使用通用矢量大小类型的最佳方法是啥?

Posted

技术标签:

【中文标题】使用通用矢量大小类型的最佳方法是啥?【英文标题】:What is the best way to use a common vector size type?使用通用矢量大小类型的最佳方法是什么? 【发布时间】:2012-01-11 18:12:02 【问题描述】:

创建模板化矢量类时,允许使用其大小类型的最佳方式是什么?从我收集到的信息来看,似乎是为真正的向量类创建一个接口,然后使用它。比如

for(VectorBase::size_type i = 0; i < test1.size(); ++i)

这比

有优势
for(Vector<int>::size_type i = 0; i < test1.size(); ++i)

用于使代码更简洁,并且不必知道 Vector 的模板类型(以防它发生变化)。

我的实现示例(如果有更好的方法,这是我创建它的方法)。

class VectorBase

public:
    typedef unsigned int size_type;

protected:
    size_type mCount;

public:
    VectorBase()  mCount = 2;  
    virtual ~VectorBase() = 0  
    size_type size() const  return mCount; 
;

template<typename Type>
class Vector : public VectorBase

public:
    Vector() : VectorBase()  
    ~Vector()  
;

int main(void)

    Vector<int> test1;

    for(VectorBase::size_type i = 0; i < test1.size(); ++i)
    
        cout << i << endl;
    

    system("PAUSE");

    return(0);

(注意:请不要把它变成“Just use xxx vector class”)。

【问题讨论】:

如果发现您希望 size_type 依赖于您的模板参数会怎样? 我更喜欢通过迭代器访问而不是索引访问——它更通用、更灵活,除非实际的索引值本身具有某种意义。 @Grizzly,我不担心我的 size_type 来自模板参数。它永远是一样的。 @Kerrek SB,我同意大多数情况下应该使用迭代器。这是为了演示 size_type 的使用方式,并且想知道应该以哪种方式访问​​它。 【参考方案1】:

不必知道 Vector 的模板类型(以防它发生变化)。

如果您担心容器类型发生变化,可以:

    为其创建一个 typedef,因此 test1 使用循环中使用的相同类型名称声明,但该名称表示的类型将来可能会更改。 编写适当的泛型函数,因此容器的类型是模板参数T 或其他类型,并且您使用typename T::size_type 作为i 的类型。然后,如果类型发生变化,您的代码就会应对。

(1)的例子:

typedef vector<int> test_type;
test_type test1;
// populate the vector
for (test_type::size_type i = 0; i < test1.size(); ++i) std::cout << i << '\n';

(2)的例子:

template <typename Container>
void print_indexes(const Container &test1) 
    for (typename Container::size_type i = 0; i < test.size(); ++i) 
        std::cout << i << '\n';
    

替代解决方法:

1) 只需使用std::size_t。有点作弊,因为原则上我认为vector&lt;bool&gt; 可以有多个SIZE_MAX 元素,但没有“正确”的向量可以比这更大。

2)(仅限 C++11)使用 auto 作为 i 的类型

for (auto i = test.size(); i != 0; --i) std::cout << (test.size() - i) << '\n';

for (decltype(test.size()) i = 0; i < test1.size(); ++i) ...

我个人会遵循标准库中使用的样式,而不是为容器类模板使用公共基类。

【讨论】:

另一个人提到了你的第二点,我很感兴趣。如果我要删除 VectorBase,那么模板是“template”,我怎么能轻松向用户公开类型? @mmurphy:通常类似于template&lt;typename Type, typename SizeType = unsigned int&gt; class myvector public: typedef Type value_type; typedef SizeType size_type; ; 我怎样才能轻松访问 size_type 值呢?看起来我需要做一些类似“Vector::size_type”(当我的类型是 int 时)的事情,这部分是我关心的,尽管它可能是唯一的方式。【参考方案2】:

我认为没有最好的方法。 :-)

通过将某些部分移至公共基类,您可以简化接口,但您也可以选择模板的派生类或特化。

例如,如果您希望 vector&lt;char&gt; 包含大量字符,则可能需要 long long 大小类型。 vector&lt;my_huge_type&gt; 的潜在专业化可能只需要 int

我们是否应该预先决定 unsigned int 总是足够好?也许,也许不是。经常设计界面以在复杂性和灵活性之间找到良好的平衡。

【讨论】:

你提出了一个很好的观点。因此,如果我要删除 VectorBase,然后让模板为“template”,我怎样才能轻松地将类型公开给用户? std::vector 有一个 typedef(没有作为模板参数的类型)。如果他们想要(不太可能:-),这允许专业化具有不同的 typedef。通过将其设为模板参数,您可以允许Vector&lt;char, int&gt;Vector&lt;char, long&gt;,这似乎是太多 的灵活性。 :-) @Bo:带符号的大小类型绝对是太灵活了! 我非常怀疑是否存在,但有没有办法只有无符号大小? 我使用带符号的类型只是为了表明它一个让 size_type 与 ptrdiff_t 相同的选项。标准容器没有这个部分是因为这会将 vector 限制为“仅”一半的地址空间,部分是因为标准委员会对于什么是真正的最佳选择没有达成共识.【参考方案3】:

既然已经有了完美的Vector,为什么还要重写?

如果您确实必须从 VectorBase 继承,但最好给 VectorBase 一个受保护的析构函数而不是一个公共虚拟析构函数,因为现在您已经给 Vector 一个 v-table。

顺便说一句,纯虚拟析构函数的语法不是标准的。

在每个向量模板中保留 size_type 的 typedef 没有编译器开销(即膨胀),因此移动它不会有很大的优势。

【讨论】:

@CashCow,我的最后一行是“(注意:请不要把它变成“只需使用 xxx 向量类。”)。我的纯虚拟析构函数怎么不标准? 虽然有些编译器允许,但标准中不允许在 = 0 后面加上 。 那应该怎样, = 0?

以上是关于使用通用矢量大小类型的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

在通用类的层次结构中使用访问者模式的最佳方法是啥?

克隆/深度复制 .NET 通用 Dictionary<string, T> 的最佳方法是啥?

使用联合类型进行类型推断 - 不存在最佳通用类型

确定当前 PowerShell 脚本位置的最佳方法是啥?

确定不再需要哪些源文件的最佳方法是啥?

C# - 获取通用列表的项目类型