方圆圆*_*方圆圆 6 c++ language-lawyer c++17 structured-bindings
考虑以下代码:
#include <utility>
#include <type_traits>
#include <cstddef>
#include <iostream>
template <typename>
struct A
{
void get() {} // #1
};
template <typename ...Ts>
struct B : A<Ts>... {};
template <typename ...Ts>
struct std::tuple_size<B<Ts...>> : std::integral_constant<std::size_t, 2> {};
template <std::size_t I, typename ...Ts>
struct std::tuple_element<I, B<Ts...>>
{
using type = int;
};
template <std::size_t I, typename ...Ts>
constexpr int get(B<Ts...>) // #2
{
return 2;
}
int main()
{
B<double, long long> b;
auto [x, y] = b;
std::cout << x << ' ' << y << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
GCC 接受上述代码并2, 2按照我的例外进行输出 ( godbolt ),但 MSVC 抱怨 ( godbolt )。
错误 C2385:“get”的访问不明确
根据cppreference:
对于每个标识符,引入一个类型为“引用
std::tuple_element<i, E>::type”的变量:如果其对应的初始值设定项是左值,则为左值引用,否则为右值引用。第 i 个变量的初始值设定项是
e.get<i>(),如果通过类成员访问查找在E范围内查找标识符 get 至少找到一个声明,该声明是第一个模板参数是非类型参数的函数模板- 否则,
get<i>(e), whereget仅通过参数相关查找来查找,忽略非 ADL 查找。
根据我的理解,成员get()(第 #1 行)不满足引用的要求(它甚至不是模板),编译器应该选择非成员get()(第 #2 行)。GCC 按照我的方式工作,但 MSVC 似乎停留在 member 上get(),忽略了它是否符合资格。
哪个编译器是正确的?为什么 MSVC 认为不符合get()结构化绑定条件?
get如果在 范围内搜索名称时E发现至少一个声明是函数模板,且其第一个模板参数是非类型参数,则初始值设定项为e.get<i>()。
(E在本例中是支持变量的类型B<double, long long>。)
如果搜索结果在不同基数的成员之间存在歧义,我们会点击[class.member.lookup]/6,从而使程序格式错误(无论找到的声明是否属于函数模板)。
CWG2567密切相关:它在查找重载运算符的上下文中处理类似的场景。
get根据该问题的拟议解决方案,该程序的结构良好:对in的搜索B<double, long long>将优雅地失败(不会产生任何结果),从而允许将非成员get用作后备。
| 归档时间: |
|
| 查看次数: |
188 次 |
| 最近记录: |