【问题标题】:static const std::vector静态常量 std::vector
【发布时间】:2012-12-07 14:42:19
【问题描述】:

我正在用 Qt 编写一个图像查看器。 我正在尝试在头文件中执行以下操作:

class ImageModel
{


private:
    const static std::vector<int> mZoomLevels;

}

在源文件中:

int zooms[] = {1,2,3,4,5,6,7,8,9,10};
const std::vector<int> mZoomLevels(zooms.begin(),zooms.end());

但是我收到以下错误:

在非类类型“int[10]”的缩放中请求成员“开始” 在非类类型“int [10]”的缩放中请求成员“结束”

有谁知道如何初始化这个静态常量私有成员?

【问题讨论】:

  • 应该是const std::vector&lt;int&gt; ImageModel::mZoomLevels(...) 吗?

标签: c++ static constants private-members


【解决方案1】:

普通数组没有成员函数。我相信你正在寻找这个:

int zooms[] = {1,2,3,4,5,6,7,8,9,10};
const std::vector ImageModel::mZoomLevels(zooms, zooms + 10);

【讨论】:

  • 感谢您的快速回答!
【解决方案2】:

数组没有beginend 成员。 begin 可以使用数组名,末尾可以使用数组名加长度:

const std::vector mZoomLevels(zooms, zooms+10);

在C++11中,你可以使用std::beginstd::end,像这样:

const std::vector mZoomLevels(std::begin(zooms), std::end(zooms));

在这两种情况下,最好声明您的 zooms 数组文件静态或将其隐藏在命名空间中,以确保其名称不会“污染”全局命名空间。

【讨论】:

  • 如果你有C++11,想要初始化向量,就不需要创建数组,使用list-initialization即可:const std::vector&lt;int&gt; ImageModel::mZoomLevels{1,2,3,4...};--更少的代码,你删除了一个不需要的数组。也就是说,如果您真的想使用std::vector&lt;int&gt;...我不太确定...
【解决方案3】:

zooms 是一个没有成员和方法的 C 样式数组,即 zooms.beginzooms.end 没有意义。如果您使用兼容 C++11 的编译器,请尝试 std::begin(zooms)std::end(zooms)

【讨论】:

    【解决方案4】:

    普通 C++ 数组不能有成员。但是,您正在寻找静态分派,并且可以通过参数类型进行重载解析。所以 C++11 提供了std::beginstd::end 非成员函数。 (这已经提到了。)

    习惯如下调用非成员函数的最佳实践(这对您编写通用模板代码很有帮助):

    using std::begin;
    using std::end;
    
    const std::vector mZoomLevels(begin(zooms), end(zooms));
    

    无论zooms 是什么类型的容器,这都能正常工作,并且它会利用ADL(依赖于参数的查找,有时称为Koenig 查找)来查找beginend 的实现。如果 zooms 有一些自定义类类型,则命名空间。

    顺便说一句,std::beginstd::end 由 C++11 提供,但您可以轻松地为早期版本编写自己的代码:

    template <typename T, size_t N>
    T* begin( T (&a)[N] ) { return a; }
    
    template <typename T, size_t N>
    T* end( T (&a)[N] ) { return a + N; }
    

    【讨论】:

    • 为什么是using?这里不需要 ADL。
    • @DeadMG:为什么不using?如果他养成正确操作的习惯,在模板中使用它时不会突然出现问题。
    • 模板不会改变任何东西。他在原生数组上调用它——std::beginstd::end 将始终被选中。
    • @DeadMG:想想zooms 是参数而不是全局变量的情况,并且参数类型被模板化以允许任何容器类型。问题中的代码是 SSCE,不一定像可能遇到的实际情况那样复杂。
    • @DeadMG:当不需要 ADL 时为什么要usingusing 指令将符号带入范围,这几乎与 ADL 正交...如果您需要 ADL 支持,您需要它,但这不是 only 目的使用声明。
    【解决方案5】:

    根据您是否可以访问 C++11,我将在此处采用不同的方法。

    在 C++03 中,我会使用一个普通数组(因为它是 const),甚至可能不在类中,而是在实现文件中的私有命名空间中(因为它是私有的,假设只有一个翻译unit 具有ImageModel 成员的定义。

    // cpp
    namespace {
       static int gZoomLevels[] = { 1, 2, ... };
    }
    

    如果您真的想继续使用 std::vector&lt;int&gt; 方法,我将在定义成员的翻译单元中创建一个辅助函数,并使用它来创建 std::vector,而无需创建具有静态持续时间的不同变量:

    namespace {
       static std::vector<int> chooseANameForInitializer() {
           int data[] = { 1, 2, 3 };
           return std::vector<int>( data, data + (sizeof data/sizeof *data) );
       }
    }
    const std::vector<int> ImageModel::mZoomLevels = chooseANameForInitializer();
    

    在 C++11 中,我会改用 std::array&lt;int,...&gt;,因为这样可以避免动态分配和额外间接的开销。当然,这不是一个很大的收获,但是当您不需要它提供的任何功能时,拥有std::vector&lt;int&gt; 是没有意义的。

    class ImageModel
    {
    private:
        static const std::array<int,10> mZoomLevels;  
    };
    // cpp:
    const std::array<int,10> ImageModel::mZoomLevels = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    

    同样,如果您坚持使用 std::vector&lt;int&gt;,那么您可以使用 list-initialization

    const std::vector<int> ImageModel::mZoomLevels{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-27
      • 1970-01-01
      • 2013-11-18
      相关资源
      最近更新 更多