C++ 静态常量std::vector

C++ 静态常量std::vector,c++,static,constants,private-members,C++,Static,Constants,Private Members,我正在用Qt编写一个图像查看器。 我正在尝试在头文件中执行以下操作: class ImageModel { private: const static std::vector<int> mZoomLevels; } 类图像模型 { 私人: 常量静态标准::向量mZoomLevels; } 在源文件中: int zooms[] = {1,2,3,4,5,6,7,8,9,10}; const std::vector<int> mZoomLevels(zoom

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

class ImageModel
{


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

}
类图像模型
{
私人:
常量静态标准::向量mZoomLevels;
}
在源文件中:

int zooms[] = {1,2,3,4,5,6,7,8,9,10};
const std::vector<int> mZoomLevels(zooms.begin(),zooms.end());
int缩放[]={1,2,3,4,5,6,7,8,9,10};
const std::vector mZoomLevels(zooms.begin(),zooms.end());
但是,我得到以下错误:

在非类类型“int[10]”的缩放中请求成员“begin” 在非类类型“int[10]”的缩放中请求成员“end”


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

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

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

数组没有
begin
end
成员。您可以将数组名用于
开始
,将数组名加上长度用于结束:

const std::vector mZoomLevels(zooms, zooms+10);
在C++11中,您可以使用和,如下所示:

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

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

缩放是一个没有成员和方法的C样式数组,即
缩放.begin
缩放.end
没有意义。如果使用C++ 11兼容编译器,请尝试<代码> STD::开始(ZOMS)和 STD::(ZoOM)< /C> < /P> < P>普通C++数组不能有成员。然而,您正在寻找静态分派,这可以通过参数类型进行重载解析。因此C++11提供了
std::begin
std::end
非成员函数。(这一点已经提到。)

按照以下方式习惯调用非成员函数的最佳实践(在编写通用模板代码时确实很有帮助):

无论容器
缩放的是什么类型,这都将正常工作,并且如果
缩放的
具有某种自定义类类型,它将利用ADL(参数相关查找,有时称为Koenig查找)在同一命名空间中查找
开始
结束
的实现

顺便说一句,
std::begin
std::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; }
模板
T*begin(T(&a)[N]){returna;}
模板
T*end(T(&a)[N]){返回a+N;}

根据您是否有权访问C++11,我将采用不同的方法

在C++03中,我将使用普通数组(因为它是常量),甚至可能不在类中,而是在实现文件中的私有名称空间中(因为它是私有的,假设只有一个转换单元具有
ImageModel
的成员定义)

如果您真的想继续使用
std::vector
方法,我会在翻译单元中创建一个定义成员的助手函数,并使用该函数创建
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();
名称空间{
静态std::vector chooseANameForInitializer(){
int data[]={1,2,3};
返回std::vector(数据,数据+(sizeof data/sizeof*data));
}
}
常量std::vector ImageModel::mZoomLevel=chooseANameForInitializer();
在C++11中,我将使用
std::array
,因为这样可以避免动态分配和额外间接寻址的开销。虽然这不是一个很大的收获,但是当您不需要它提供的任何功能时,拥有一个
std::vector
是没有意义的

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::数组mZoomLevels;
};
//cpp:
常量std::array ImageModel::mZoomLevel={1,2,3,4,5,6,7,8,9};
同样,如果您坚持使用
std::vector
,则可以使用列表初始化

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

为什么使用
?这里不需要ADL。@DeadMG:为什么不使用
?如果他养成了正确操作的习惯,在模板中使用它时不会突然出现问题。模板不会改变任何东西。他在本机数组上调用它-
std::begin
std::end
将始终被选中。@DeadMG:想想这样的情况,
zooms
是一个参数,而不是全局变量,参数类型被模板化以允许任何容器类型。问题中的代码是SSCE,不一定像可能遇到的实际情况那样复杂。@DeadMG:当不需要ADL时,为什么使用
?using指令将符号引入范围,该符号几乎与ADL正交。。。如果您想要ADL支持,当然需要它,但这不是使用声明的唯一目的。应该是
const std::vector ImageModel::mZoomLevels(…)
?谢谢您的快速回答!如果您有C++11并且想要初始化向量,则无需创建数组,只需使用列表初始化:
const std::vector ImageModel::mZoomLevels{1,2,3,4…}--代码越少,就可以删除不需要的数组。如果您真的想使用
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();
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 };
const std::vector<int> ImageModel::mZoomLevels{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };