std :: vector范围构造函数可以调用显式转换吗?


14

以下程序格式正确吗?

#include <vector>
struct A {
    explicit A(int) {}
};
int main() {
    std::vector<int> vi = {1, 2, 3, 4, 5};
    std::vector<A> va(vi.begin(), vi.end());
}

根据C ++ 17 [sequence.reqmts],对于

X u(i, j);

X序列容器在哪里,是:

TEmplaceConstructibleX*i

但是,在上段中指出:

ij表示满足输入迭代器要求的迭代器,并且是指可隐式转换为的元素value_type

因此,在我看来,这两个要求都必须满足:范围的值类型必须隐式转换为容器的值类型,并且 EmplaceConstructible必须满足(这意味着分配器必须能够执行所需的初始化) 。由于int不能隐式转换为A,因此该程序应格式错误。

但是,令人惊讶的是,它似乎可以在GCC下进行编译


(根据记录,不仅是gcc:godbolt.org/z/ULeRDw
Max Langhof,

在这种情况下,不需要任何隐式转换,因为显式构造函数已经适合该类型。我认为描述令人困惑,但是显式构造总是比构造之前的隐式转换更好。
JHBonarius

Answers:


2

仅要求序列容器支持满足隐式可转换标准的迭代器的构造。

这本身并没有不允许序列容器从支持从不满足该标准,据我可以告诉迭代器建设1。关于此有明确的规则:

如果使用不符合输入迭代器资格的 InputIterator类型调用构造函数... ,则构造函数不得参与重载解析。

目前尚不清楚“限定为输入迭代器”在上下文中到底是什么意思。是表达Cpp17InputIterator的非正式方法,还是试图引用i和j的要求?我不知道。无论是否允许,标准都没有严格的检测要求:

[container.requirements.general]

某些容器成员函数和推论指南的行为取决于类型是否符合输入迭代器或分配器的条件。未确定实现确定类型不能为输入迭代器的程度,除非作为最小整数类型不符合输入迭代器的条件。...

通过解释任何Cpp17InputIterator“有资格作为输入迭代器”,示例程序就不需要格式错误。但这也不保证格式正确。

1在这种情况下,依靠它来警告可能会被视为实施质量问题。另一方面,这种对隐式转换的限制可能被认为是缺陷


PS这将在Clang(使用libc ++)和Msvc中进行编译而不会发出警告。

PPS这个措辞似乎是在C ++ 11中添加的(这很自然,因为随后也引入了显式构造函数)。


1
真正取决于“没有资格作为输入迭代器”的含义。与上述不同,它实际上并未说出Cpp17InputIterator,因此我不清楚“输入迭代器”中是否包含“并引用隐式转换为value_type”的元素。如果是这样,则构造函数不应参与重载解析,并且程序应格式错误。
马克斯·朗霍夫

1
那么,每个标准库类都可以使用额外的构造函数,而在使用这些额外的构造函数时不会发出诊断?从直觉上看,这对我来说是错的……
Brian

@Brian我不确定它是否是“额外的构造函数”,但可能更多的是“允许更多空间的特定构造函数实现”。检查每个输入可能会对性能产生重大影响,所以我不知道这是否
可行

@Brian即使没有明确禁止,这肯定不是一个好主意。在这种情况下,我们仅考虑是否允许所需的构造函数支持不需要支持的迭代器类型。在这种情况下,正如Max指出的那样,存在明确的“不得参与”要求,这肯定会不允许这样做。但是确实不清楚“限定为输入迭代器”在上下文中到底是什么意思。它是表达非正式的方式Cpp17InputIterator,或是否试图引用的要求ij?我不知道。
eerorika

2
1)在C ++中,我们将标准设置为低。。2)构造函数是非虚拟成员函数。3)参见LWG 3297;但是我并不特别相信我们应该删除隐式转换要求。
TC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.