如何让非成员 get<N> 在命名空间 [C++17] 中为自定义 class 工作
How to get non-member get<N> to work for custom class in a namespace [C++17]
C++17 引入了结构化绑定声明:auto [a, b] = some_tuple;
.
这对于 std::tuple 之类的东西来说是开箱即用的。也可以使其适用于自定义类型,您只需提供(除其他事项外)一个 get-function 模板,作为成员或在自定义 class.
之外
对于标准 classes,这是通过位于 std-namespace 中的非成员 get 完成的:auto a = std::get<0>(some_tuple);
有效,但 auto a = some_tuple.get<0>();
无效。
但是这里对我来说很奇怪:因为我们必须明确指定get的模板参数N,所以ADL不起作用,例如,我们不能只写auto a = get<0>(some_tuple);
。但是,带有元组的结构化绑定声明也不应该起作用,因为它只是调用 get<N>(some_tuple)
或 some_tuple.get<N>()
(对某些 &
取模)的语法糖! 事实上,当我在命名空间内为我的自定义 class 提供非成员版本的 get 时,它不起作用! 编辑: 自定义 classes 的结构化绑定也可以正常工作,请参阅已接受答案中的代码片段以获取最小示例!
那么标准的实施者如何使结构化绑定工作,例如没有 get as 成员的元组,我怎样才能为我的自定义 classes 实现相同的行为?
他们作弊。
但是您可以通过向全局命名空间添加模板 get 来模拟他们的作弊行为。
template<class T, std::enable_if_t<std::is_same<T,void>{}, bool>>
void get(int)=delete;
应该激活 "parse get as a template"。
您无需执行此操作即可使结构化绑定正常工作。如前所述,the compiler just cheats:
namespace example {
struct silly {
int x;
};
template<std::size_t I>
int& get( silly& s ) { return s.x; }
}
namespace std {
template<>
struct tuple_size<::example::silly>:std::integral_constant<std::size_t, 1>{};
template<>
struct tuple_element<0, ::example::silly>{ using type=int; };
}
int main() {
example::silly s { 42 };
auto&& [x] = s;
std::cout << x;
}
C++17 引入了结构化绑定声明:auto [a, b] = some_tuple;
.
这对于 std::tuple 之类的东西来说是开箱即用的。也可以使其适用于自定义类型,您只需提供(除其他事项外)一个 get-function 模板,作为成员或在自定义 class.
之外对于标准 classes,这是通过位于 std-namespace 中的非成员 get 完成的:auto a = std::get<0>(some_tuple);
有效,但 auto a = some_tuple.get<0>();
无效。
但是这里对我来说很奇怪:因为我们必须明确指定get的模板参数N,所以ADL不起作用,例如,我们不能只写auto a = get<0>(some_tuple);
。但是,带有元组的结构化绑定声明也不应该起作用,因为它只是调用 get<N>(some_tuple)
或 some_tuple.get<N>()
(对某些 &
取模)的语法糖! 事实上,当我在命名空间内为我的自定义 class 提供非成员版本的 get 时,它不起作用! 编辑: 自定义 classes 的结构化绑定也可以正常工作,请参阅已接受答案中的代码片段以获取最小示例!
那么标准的实施者如何使结构化绑定工作,例如没有 get as 成员的元组,我怎样才能为我的自定义 classes 实现相同的行为?
他们作弊。
但是您可以通过向全局命名空间添加模板 get 来模拟他们的作弊行为。
template<class T, std::enable_if_t<std::is_same<T,void>{}, bool>>
void get(int)=delete;
应该激活 "parse get as a template"。
您无需执行此操作即可使结构化绑定正常工作。如前所述,the compiler just cheats:
namespace example {
struct silly {
int x;
};
template<std::size_t I>
int& get( silly& s ) { return s.x; }
}
namespace std {
template<>
struct tuple_size<::example::silly>:std::integral_constant<std::size_t, 1>{};
template<>
struct tuple_element<0, ::example::silly>{ using type=int; };
}
int main() {
example::silly s { 42 };
auto&& [x] = s;
std::cout << x;
}