问题描述
在显式构造 std :: initializer_list< U>
时,可以推导出模板参数( U
) (例如,使用类模板参数推导(CTAD))?
When constructing an std::initializer_list<U>
explicitly, can the template argument (U
) be deduced (using class template argument deduction (CTAD), for example)?
换句话说,我知道以下语句是有效的:
In other words, I know that the following statements are valid:
std::initializer_list<int> x1{1, 2, 3};
std::initializer_list<int> x2 = {1, 2, 3};
auto x3 = std::initializer_list<int>{1, 2, 3};
但是以下语句也有效吗?
but are the following statements also valid?
std::initializer_list x1{1, 2, 3};
std::initializer_list x2 = {1, 2, 3};
auto x3 = std::initializer_list{1, 2, 3};
编译器不同意<$的模板参数可以推断出c $ c> std :: initializer_list :
#include <initializer_list>
struct s {
s(std::initializer_list<int>);
};
void f() {
std::initializer_list x1{1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
std::initializer_list x2 = {1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
auto x3 = std::initializer_list{1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
s x4(std::initializer_list{1, 2, 3}); // Clang ERROR; GCC ERROR; MSVC OK
s x5{std::initializer_list{1, 2, 3}}; // Clang ERROR; GCC OK; MSVC OK
s x6 = s(std::initializer_list{1, 2, 3}); // Clang ERROR; GCC OK; MSVC OK
s x7 = s{std::initializer_list{1, 2, 3}}; // Clang ERROR; GCC OK; MSVC OK
s x8 = std::initializer_list{1, 2, 3}; // Clang ERROR; GCC OK; MSVC OK
void g(std::initializer_list<int>);
g(std::initializer_list{1, 2, 3}); // Clang ERROR; GCC OK; MSVC OK
}
(请参见。)
经过测试的编译器:
- 使用
-std = c ++ 17 -stdlib = libc ++
和的Clang版本7.0.0 -std = c ++ 17 -stdlib = libstdc ++
- GCC版本8.3与
-std = c ++ 17
- MSVC版本19.16,具有
/ std:c ++ 17
- Clang version 7.0.0 with
-std=c++17 -stdlib=libc++
and with-std=c++17 -stdlib=libstdc++
- GCC version 8.3 with
-std=c++17
- MSVC version 19.16 with
/std:c++17
推荐答案
Clang是唯一正确的编译器。是的,真的。
Clang is the only compiler that is correct. Yes, really.
当编译器看到没有模板参数的模板名称时,它必须查看模板的推导指南并将其应用于括号中的参数。 -init-list。 initializer_list
没有任何明确的推论指南,因此它使用可用的构造函数。
When the compiler sees a template name without template parameters, it has to look at the deduction guides of the template and apply them to the arguments in the braced-init-list. initializer_list
doesn't have any explicit deduction guides, so it uses the available constructors.
唯一可公开访问的构造函数 initializer_list
具有的是其复制/移动构造函数及其默认构造函数。不能通过可公开访问的构造函数来从括号初始列表创建 std :: initializer_list
。通过完成,这是仅限编译器进程。只有编译器才能执行。
The only publicly accessible constructors that an initializer_list
has are its copy/move constructors and its default constructor. Creating a std::initializer_list
from a braced-init-list isn't done through publicly accessible constructors. It's done through list-initialization, which is a compiler-only process. Only the compiler can perform the sequence of steps needed to build one.
鉴于所有这些,除非您在 initializer_list
上使用CTAD,否则应该是不可能的从现有列表中复制。最后一部分可能是其他编译器在某些情况下如何使其工作。在推论方面,他们可以将括号初始列表推导为 initializer_list< T>
本身,而不是推导到,因此推论指南会看到复制操作。
Given all of this, it should not be possible to use CTAD on initializer_list
s, unless you're copying from an existing list. And that last part is probably how the other compilers make it work in some cases. In terms of deduction, they may deduce the braced-init-list as an initializer_list<T>
itself rather than as a sequence of parameters to apply [over.match.list] to, so the deduction guide sees a copy operation.
这篇关于std :: initializer_list {x,y,z}(CTAD)有效吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!