C ++ 11初始化程序列表失败 - 但只在长度为2的列表上 [英] C++11 initializer list fails - but only on lists of length 2

查看:95
本文介绍了C ++ 11初始化程序列表失败 - 但只在长度为2的列表上的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我跟踪了一个模糊的记录错误,因为长度为2的初始化器列表似乎是一个特殊的情况!

I tracked down an obscure logging bug to the fact that initializer lists of length 2 appear to be a special case! How is this possible?

代码是使用Apple LLVM版本5.1(clang-503.0.40)编译的,使用 CXXFLAGS = -std = c ++ 11 -stdlib = libc ++

The code was compiled with Apple LLVM version 5.1 (clang-503.0.40), using CXXFLAGS=-std=c++11 -stdlib=libc++.

#include <stdio.h>

#include <string>
#include <vector>

using namespace std;

typedef vector<string> Strings;

void print(string const& s) {
    printf(s.c_str());
    printf("\n");
}

void print(Strings const& ss, string const& name) {
    print("Test " + name);
    print("Number of strings: " + to_string(ss.size()));
    for (auto& s: ss) {
        auto t = "length = " + to_string(s.size()) + ": " + s;
        print(t);
    }
    print("\n");
}

void test() {
    Strings a{{"hello"}};                  print(a, "a");
    Strings b{{"hello", "there"}};         print(b, "b");
    Strings c{{"hello", "there", "kids"}}; print(c, "c");

    Strings A{"hello"};                    print(A, "A");
    Strings B{"hello", "there"};           print(B, "B");
    Strings C{"hello", "there", "kids"};   print(C, "C");
}

int main() {
    test();
}

输出:

Test a
Number of strings: 1
length = 5: hello

Test b
Number of strings: 1
length = 8: hello

Test c
Number of strings: 3
length = 5: hello
length = 5: there
length = 4: kids

Test A
Number of strings: 1
length = 5: hello

Test B
Number of strings: 2
length = 5: hello
length = 5: there

Test C
Number of strings: 3
length = 5: hello
length = 5: there
length = 4: kids

测试b中的伪字符串的长度似乎是不确定的 - 它总是大于第一个初始化字符串,但是从初始化器中的第一个字符串的长度变化到两个字符串的长度的总和。

I should also add that the length of the bogus string in test b seems to be indeterminate - it's always greater than the first initializer string but has varied from one more than the length of the first string to the total of the lengths of the two strings in the initializer.

推荐答案

简介



想象下面的声明和用法: / p>

Introduction

Imagine the following declaration, and usage:

struct A {
  A (std::initializer_list<std::string>);
};

A {{"a"          }}; // (A), initialization of 1 string
A {{"a", "b"     }}; // (B), initialization of 1 string << !!
A {{"a", "b", "c"}}; // (C), initialization of 3 strings

和( C ),每个 c风格字符串都会导致一个(1) std :: string 的初始化,

In (A) and (C), each c-style string is causing the initialization of one (1) std::string, but, as you have stated in your question, (B) differs.

编译器发现可以构建一个 std :: string 使用 begin - end-iterator ,在解析语句( B )时, c>a和b作为两个元素的个别初始值。

The compiler sees that it's possible to construct a std::string using a begin- and end-iterator, and upon parsing statement (B) it will prefer such construct over using "a" and "b" as individual initializers for two elements.

A { std::string { "a", "b" } }; // the compiler's interpretation of (B)



注意ab char const [2] ,可以隐式衰减为 / code>,这是一种指针类型,适用于当 begin 或 end 的迭代器。 cppreference.com/w/cpp/string/basic_string/basic_string\">创建std :: string .. ,我们必须小心:我们正在导致 undefined-behavior ,因为在调用所述构造函数时两个指针之间没有(保证)关系。

Note: The type of "a" and "b" is char const[2], a type which can implicitly decay into a char const*, a pointer-type which is suitable to act like an iterator denoting either begin or end when creating a std::string.. but we must be careful: we are causing undefined-behavior since there is no (guaranteed) relation between the two pointers upon invoking said constructor.






说明



当您使用双大括号调用构造函数时,采用 std :: initializer_list {{a,b,...}} 有两种可能的解释:


Explanation

When you invoke a constructor taking an std::initializer_list using double braces {{ a, b, ... }}, there are two possible interpretations:


  1. 外部大括号指构造函数本身,内部大括号表示要参与 std :: initializer_list 的元素,或:

外部大括号指的是 std :: initializer_list ,而内部大括号表示内部元素的初始化。

The outer braces refer to the std::initializer_list, whereas the inner braces denotes the initialization of an element inside it.

只要可能就可以执行 2) $ c> std :: string 有一个带两个迭代器的构造函数,当你有 std :: vector< std :: string> {{hello,there}}

It's prefered to do 2) whenever that is possible, and since std::string has a constructor taking two iterators, it is the one being called when you have std::vector<std::string> {{ "hello", "there" }}.


$ b

Further example:

std::vector<std::string> {{"this", "is"}, {"stackoverflow"}}.size (); // yields 2






解决方案



不要使用双括号进行初始化。


Solution

Don't use double braces for such initialization.

这篇关于C ++ 11初始化程序列表失败 - 但只在长度为2的列表上的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆