在C++标准§13.3.1.7[over.match.list]中,陈述如下:
在copy-list-initialization中,如果
explicit选择了构造函数,则初始化是错误的.
这就是为什么我们不能这样做的原因,例如:
struct foo {
// explicit because it can be called with one argument
explicit foo(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
f({ "answer", 42 });
Run Code Online (Sandbox Code Playgroud)
(注意,这里发生的不是转换,即使构造函数是"隐式的"也不会是一个.这是一个foo对象直接使用它的构造函数初始化.除此之外std::string,这里没有转换.)
这对我来说似乎完全没问题.隐式转换不会让我感到困惑.
如果{ "answer", 42 }可以初始化其他东西,编译器不会背叛我并做错事:
struct bar {
// explicit because it can be called with one argument
explicit bar(std::string s, int x = 0);
private:
// ...
};
void f(foo x);
void f(bar x); …Run Code Online (Sandbox Code Playgroud) 出于某种原因,我认为C++ 0x允许std::initializer_list作为函数的函数参数,例如,期望可以从这样构造的类型std::vector.但显然,它不起作用.这只是我的编译器,还是永远不会起作用?是因为潜在的重载解决问题吗?
#include <string>
#include <vector>
void function(std::vector<std::string> vec)
{
}
int main()
{
// ok
std::vector<std::string> vec {"hello", "world", "test"};
// error: could not convert '{"hello", "world", "test"}' to 'std::vector...'
function( {"hello", "world", "test"} );
}
Run Code Online (Sandbox Code Playgroud) 假设您正在编写一个接受被std::initializer_list调用list的函数,并且该函数需要随机访问其list元素.写list[i]代替是方便的list.begin()[i].那么为什么不std::initializer_list提供定义operator[]呢?
我想不出任何operator[]返回const T&不明确的情况.效率在这里似乎不是问题,因为std::initializer_list<T>::iterator别名const T*,显然是随机访问迭代器.
考虑功能:
template<typename T>
void printme(T&& t) {
for (auto i : t)
std::cout << i;
}
Run Code Online (Sandbox Code Playgroud)
或任何其他期望一个参数具有begin()/ end()启用类型的函数.
以下为什么违法?
printme({'a', 'b', 'c'});
当所有这些都合法时:
printme(std::vector<char>({'a', 'b', 'c'}));
printme(std::string("abc"));
printme(std::array<char, 3> {'a', 'b', 'c'});
Run Code Online (Sandbox Code Playgroud)
我们甚至可以这样写:
const auto il = {'a', 'b', 'c'};
printme(il);
Run Code Online (Sandbox Code Playgroud)
要么
printme<std::initializer_list<char>>({'a', 'b', 'c'});
Run Code Online (Sandbox Code Playgroud) 也就是说,为什么这样:
struct S {};
struct T
{
T(S& s) : s{s} {}
S& s;
};
int main()
{
S s;
T t{s};
}
Run Code Online (Sandbox Code Playgroud)
给我一个GCC 4.7的编译器错误:
test.cpp: In constructor 'T::T(S&)':
test.cpp:5:18: error: invalid initialization of non-const reference of type 'S&' from an rvalue of type '<brace-enclosed initializer list>'
Run Code Online (Sandbox Code Playgroud)
?
要修复错误,我必须更改s{s}为s(s).这不会打破统一初始化的统一性吗?
编辑:我试过clang,clang接受它,所以也许这是一个GCC错误?
考虑一下这个C++ 11代码片段:
#include <iostream>
#include <set>
#include <stdexcept>
#include <initializer_list>
int main(int argc, char ** argv)
{
enum Switch {
Switch_1,
Switch_2,
Switch_3,
Switch_XXXX,
};
int foo_1 = 1;
int foo_2 = 2;
int foo_3 = 3;
int foo_4 = 4;
int foo_5 = 5;
int foo_6 = 6;
int foo_7 = 7;
auto get_foos = [=] (Switch ss) -> std::initializer_list<int> {
switch (ss) {
case Switch_1:
return {foo_1, foo_2, foo_3};
case Switch_2:
return {foo_4, foo_5};
case Switch_3: …Run Code Online (Sandbox Code Playgroud) 为什么st_ :: initializer_list <_E> :: size在static_assert中是不允许的,即使它在我的libstdc ++(v.4.6)中被声明为constexpr?
例如,以下代码:
template<class T, int Length>
class Point
{
public:
Point(std::initializer_list<T> init)
{
static_assert(init.size() == Length, "Wrong number of dimensions");
}
};
int main()
{
Point<int, 3> q({1,2,3});
return 0;
}
Run Code Online (Sandbox Code Playgroud)
给出以下错误:
test.C: In constructor ‘Point<T, Length>::Point(std::initializer_list<_Tp>) [with T = int, int Length = 3]’:
test.C:60:26: instantiated from here
test.C:54:7: error: non-constant condition for static assertion
test.C:54:73: in constexpr expansion of ‘init.std::initializer_list<_E>::size [with _E = int, std::initializer_list<_E>::size_type = long unsigned int]()’
test.C:54:7: error: ‘init’ …Run Code Online (Sandbox Code Playgroud) 我在这里问了一个问题:涉及非功能代码的initializer_list返回的生命周期扩展:
const auto foo = [](const auto& a, const auto& b, const auto& c) { return {a, b, c}; };
Run Code Online (Sandbox Code Playgroud)
我相信lambda试图回归intializer_list(这很糟糕,不要这样做.)但我得到了一个评论:
它不是一个
initializer_list,它是一个初始化列表.两件不同的事情.
我只是认为,无论何时你做了一个花括号列表,你都在创建一个intializer_list.如果那不是正在发生的事情,花括号中的列表是什么?
c++ initialization initializer curly-braces initializer-list
我一直想知道可变参数比初始化列表有什么优点.两者都提供相同的能力 - 将无限数量的参数传递给函数.
我个人认为初始化列表更优雅一些.语法不那么尴尬.
此外,随着参数数量的增加,初始化程序列表似乎具有明显更好的性能.
所以除了在C中使用可变参数的可能性之外我还缺少什么?
考虑一下代码
#include <iostream>
class Foo
{
int val_;
public:
Foo(std::initializer_list<Foo> il)
{
std::cout << "initializer_list ctor" << std::endl;
}
/* explicit */ Foo(int val): val_(val)
{
std::cout << "ctor" << std::endl;
};
};
int main(int argc, char const *argv[])
{
// why is the initializer_list ctor invoked?
Foo foo {10};
}
Run Code Online (Sandbox Code Playgroud)
输出是
ctor
initializer_list ctor
Run Code Online (Sandbox Code Playgroud)
据我所知,该值10被隐式转换为Foo(第一个ctor输出),然后初始化构造函数启动(第二个initializer_list ctor输出).我的问题是为什么会发生这种情况?标准构造函数Foo(int)不是更好的匹配吗?也就是说,我本来希望这个片段的输出是公正的ctor.
PS:如果我将构造函数标记Foo(int)为explicit,则Foo(int)调用唯一的构造函数,因为整数10现在不能隐式转换为a Foo.
c++ ×10
initializer-list ×10
c++11 ×9
constexpr ×1
constructor ×1
curly-braces ×1
initializer ×1
iterator ×1
lambda ×1
performance ×1
reference ×1
templates ×1