标签: initializer-list

初始化包含自身向量的结构

我有一个菜单系统,我想从常量数据初始化.A MenuItem可以包含作为子菜单的向量MenuItems.但它只能达到一定程度.以下是问题的根本原因:

#include <vector>
struct S { std::vector<S> v ; } ;

S s1 = { } ;
S s2 = { { } } ;
S s3 = { { { } } } ;
Run Code Online (Sandbox Code Playgroud)

g++ -std=c++0x(版本4.4.5)应对s1s2,但s3回来:

prog.cpp:6:22: error: template argument 1 is invalid
Run Code Online (Sandbox Code Playgroud)

(见ideone).难道我做错了什么?

c++ stl initializer-list incomplete-type c++11

11
推荐指数
2
解决办法
1863
查看次数

无法使用统一初始化复制std :: vector <std :: function <void()>>.它是否正确?

以下代码无法在GCC 4.7.2或Clang 3.2中编译:

#include <vector>
#include <functional>

int main()
{
   std::vector<std::function<void()>> a;
   std::vector<std::function<void()>> b{a};
}
Run Code Online (Sandbox Code Playgroud)

问题是编译器将尝试使用initializer_list创建b,显然它应该只是调用复制构造函数.然而,这似乎是期望的行为,因为标准表明initializer_list构造函数应该优先.

这段代码适用于其他std :: vector,但对于std :: function,编译器无法知道你是否需要initializer_list构造函数或其他构造函数.

它似乎没有办法解决它,如果是这种情况,那么你永远不能在模板化代码中使用统一初始化.这将是一个巨大的耻辱.

另一方面,Visual Studio(2012年11月CTP)并没有抱怨这一点.但是此时initializer_list支持不是很好,所以它可能是一个bug.

c++ initializer-list c++11

11
推荐指数
2
解决办法
407
查看次数

传递初始化列表或容器,看向移动语义?

编辑:在我们开始之前,这个问题不是关于正确使用std::initializer_list; 它是关于在需要方便的语法时应该传递什么.谢谢你坚持主题.


C++ 11引入std::initializer_list了定义接受braced-init-list参数的函数.

struct bar {
    bar( char const * );
    bar( int );
} dog( 42 );

fn foo( std::initializer_list< bar > args );

foo( { "blah", 3, dog } );
Run Code Online (Sandbox Code Playgroud)

语法很好,但由于各种问题,它很糟糕:

  • 他们无法有意义地感动.上述功能必须dog从列表中复制; 这不能转换为移动建筑或省略.仅移动类型根本无法使用.(好吧,const_cast实际上是一个有效的解决方法.如果有一篇关于这样做的文章,我希望看到它.)

  • 也没有constexpr语义.(这在C++ 1y即将发布.但这是一个小问题.)

  • const不像其他地方那样传播; 的initializer_list是从来没有const,但它的内容始终是.(因为它不拥有其内容,所以它不能对副本进行写访问,尽管将它复制到任何地方都很少是安全的.)

  • initializer_list对象不拥有其存储(yikes); 它与提供存储的完全独立的裸阵列(yikes)的关系被隐含地定义(yikes)作为引用与绑定临时(四倍yikes)的关系.

我相信这些事情会在适当的时候得到解决,但是现在是否有最佳实践来获得没有硬编码的优势initializer_list?是否有关于直接依赖它的文献或分析?

显而易见的解决方案是通过值传递标准容器,例如std::vector.一旦将对象从中复制到其中initializer_list,它就会被移动构造为按值传递,然后您可以移出内容.改进是在堆栈上提供存储.一个好的图书馆也许能提供大部分的优点initializer_list,arrayvector,甚至不需要使用前者.

有资源吗?

c++ initializer-list c++11

11
推荐指数
1
解决办法
3427
查看次数

是否有任何C++标准的计划来解决初始化列表构造函数的不一致性?

C++中的初始化列表构造函数经常会引起麻烦; 例如

using std::vector;
using std::string;
vector<string> v{3}; // vector of three empty strings
vector<int> u{3}; // vector of one element with value 3
Run Code Online (Sandbox Code Playgroud)

(只是为了澄清,我的意思是<int>构造函数是一个初始化列表构造函数,而<string>一个不是.)

int案例与初始化列表构造函数匹配,而string案例则不匹配.这有点难看,常常会造成麻烦.在Scott Meyers的Effective Modern C++的早期章节(第7项)中也注意到了这一点,他将其描述为标准中有些令人不快的部分,每当初始化列表构造函数可用时,编译器将跳过箍尝试匹配它,优先于每个其他构造函数.

当然,int case可以通过改变u{3}来轻松修复u(3),但这不是重点.

这是理想的行为吗?C++标准委员会是否有任何讨论或计划来解决这种模糊/不愉快?一个例子是要求初始化程序列表构造函数被调用,如下所示:vector<int> u({3})这已经是合法的.

c++ constructor initializer-list c++-standard-library c++11

11
推荐指数
1
解决办法
375
查看次数

C++:我应该将构造函数体中指定的指针成员初始化为NULL吗?

假设我有:

// MyClass.h
class MyClass
{
  public:
    MyClass();

  private:
    Something *something_;
}

// MyClass.cpp
MyClass::MyClass()
{
  something_ = new Something();
}
Run Code Online (Sandbox Code Playgroud)

我应该在MyClass构造函数的构造函数初始化列表中初始化something_到NULL(或0)吗?或者这是不必要的,因为我在构造函数的主体中分配它?建议的做法是什么?

c++ constructor pointers initializer-list ctor-initializer

10
推荐指数
1
解决办法
2万
查看次数

'结构初始化程序中的多余元素'错误与C++ 11统一初始化

我对以下编译器错误感到惊讶:

template <typename T>
struct A
{
    A(T t): t_{t} {}

    T t_;
};

struct S
{
};

int main()
{
    A<S> s{S{}};
}
Run Code Online (Sandbox Code Playgroud)

错误是(与clang):

test.cpp:4:16: error: excess elements in struct initializer
    A(T t): t_{t} {}
               ^
test.cpp:15:10: note: in instantiation of member function 'A<S>::A' requested here
    A<S> s{S{}};
         ^
Run Code Online (Sandbox Code Playgroud)

GCC给出了类似的错误.

我希望表达t_{t},试图复制构建t_t.由于S有一个隐式生成的复制构造函数,我不希望这是一个问题.

有人能解释一下这里发生了什么吗?

c++ copy-constructor initializer-list uniform-initialization c++11

10
推荐指数
1
解决办法
3806
查看次数

将Variadic模板包转换为std :: initializer_list

假设有一个接受多个字符串的函数:

void fun (const std::initializer_list<std::string>& strings) {
  for(auto s : strings)
    // do something
}
Run Code Online (Sandbox Code Playgroud)

现在,我有一个可变template函数说foo():

template<typename ...Args>
void foo () {
  fun(???);
}
Run Code Online (Sandbox Code Playgroud)

此方法在外部称为:

foo<A, B, C, D>(); // where A, B, C, D are classes
Run Code Online (Sandbox Code Playgroud)

这些作为参数传递的类应该包含一个公共static const成员:

static const std::string value = "...";
Run Code Online (Sandbox Code Playgroud)

以下是我的问题(如何):

  1. 在里面foo(),检查是否所有Args包含value使用 static_assert
  2. 将所有这些值传递fun()给形成initializer_list; 例如 fun({A::value, B::value, ...});

搜索了几个与可变参数模板及其解包相关的线程,但我仍然是这个领域的新手.非常感谢更详细的解释.

c++ templates initializer-list variadic-templates c++11

10
推荐指数
1
解决办法
3919
查看次数

为什么我不能用{std :: move(first),std :: move(second)}实例化std :: vector <std :: unique_ptr <int >>?

我有一个简单的函数,它应该构造一些对象并返回它们的向量,同时还转移所有权.我认为这样做的最好方法就是返回一个std::vector<std::unique_ptr<int>>对象(让我们说它们就是这样int).

当我尝试以下功能时:

std::vector<std::unique_ptr<int>> create_stuff() {
    auto first = std::make_unique<int>(1);
    auto second = std::make_unique<int>(2);
    return {std::move(first), std::move(second)};
}
Run Code Online (Sandbox Code Playgroud)

我受到了很长的编译错误的欢迎,结果是:

xmemory0(737): error C2280: 'std::unique_ptr<int,std::default_delete<_Ty>>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)':
attempting to reference a deleted function
Run Code Online (Sandbox Code Playgroud)

我认为问题在于函数本身,但是以下解决方案工作正常:

std::vector<std::unique_ptr<int>> create_stuff() {
    auto first = std::make_unique<int>(1);
    auto second = std::make_unique<int>(2);
    std::vector<std::unique_ptr<int>> results;
    results.push_back(std::move(first));
    results.push_back(std::move(second));
    return results;
}
Run Code Online (Sandbox Code Playgroud)

为什么第二种解决方案有效但不是第一种?有没有一种解决方法可以让我在初始化列表中使用简短的语法?

c++ initializer-list unique-ptr

10
推荐指数
1
解决办法
151
查看次数

C++ 初始化列表重载消歧

我有一个关于 C++ 初始化列表消歧的问题,它在 gcc、clang 和 Visual Studio 之间表现出不同的行为。

我想知道这是“未定义的行为”(不正确的程序)还是这些编译器之一有错误。任何的想法?

考虑以下声明:

class Arg
{
public:
    Arg(int i);
};

class Object
{
public:
    Object(const char* str, int i);
    Object(const char* str, const std::initializer_list<Arg>& args);
};
Run Code Online (Sandbox Code Playgroud)

现在这种用法:

Object c("c", {4});
Run Code Online (Sandbox Code Playgroud)

应该使用哪个构造函数?一个 with int(假设文字周围的大括号是多余的)或一个带有初始化列表的(隐式转换 from intto Arg)。

GCC 10.2.0 选择具有初始化列表的构造函数Arg

Clang 11.2.2-2 选择构造函数int并报告有关大括号的警告:

initlist.cpp:46:19: warning: braces around scalar initializer [-Wbraced-scalar-init]
    Object c("c", {4});
                  ^~~
Run Code Online (Sandbox Code Playgroud)

Visual Studio 2019 16.8.6 选择int没有警告的构造函数( /W4)。

从多数人的角度来看,具有int胜利的构造函数。另一方面,如果我们直接使用std::initializer_list<int> …

c++ initializer-list compiler-bug

10
推荐指数
1
解决办法
161
查看次数

递归使用时 std::initializer_list 的生命周期

我正在尝试使用它std::initializer_list来定义和输出递归数据结构。在下面的示例中,我正在处理一个列表,其中每个元素可以是整数,也可以是同一类型列表的另一个实例。我使用中间变体类型来执行此操作,该中间变体类型可以是初始值设定项列表或整数。

我不清楚的是,它的生命周期是否std::initializer_list足够长来支持这个用例,或者我是否会遇到内存访问不一致的可能性。代码运行良好,但我担心这不能得到保证。我的希望是,用于创建最顶层列表的std::initializer_list任何中间临时std::initializer_list对象仅在顶层表达式完成后才被清除。

struct wrapped {
    bool has_list;
    int n = 0;
    std::initializer_list<wrapped> lst;

    wrapped(int n_) : has_list(false), n(n_) {}
    wrapped(std::initializer_list<wrapped> lst_) : has_list(true), lst(lst_) {}

    void output() const {
      if (!has_list) {
        std::cout << n << ' ';
      } else {
        std::cout << "[ ";
        for (auto&& x : lst)  x.output();
        std::cout << "] ";
      }
    }
  };

  void call_it(wrapped w) {
    w.output();
    std::cout << std::endl;
  }

  void call_it() {
    call_it({1});                 // …
Run Code Online (Sandbox Code Playgroud)

c++ initializer-list language-lawyer

10
推荐指数
1
解决办法
202
查看次数