如何让非会员获得 在命名空间中使用自定义类[C ++ 17]

问题描述 投票:6回答:1

C ++ 17引入了结构化绑定声明:auto [a, b] = some_tuple;

这对于像std :: tuple这样的东西来说是开箱即用的。它也可以使它适用于自定义类型,您只需提供(除其他外)一个get-function模板,作为成员或在自定义类之外。

对于标准类,这是通过位于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>()(modulo some &)调用的语法糖! 事实上,当我在命名空间内仅为我的自定义类提供非成员版本的get时,它不起作用! 编辑:自定义类的结构化绑定也可以正常工作,请参阅接受的答案中的代码片段,以获得最小的示例!

那么标准的实施者如何使结构化绑定工作于例如没有get成员的元组,我如何为自定义类实现相同的行为?

c++ std c++17 stdtuple
1个回答
7
投票

他们作弊。

但是你可以通过添加模板get到全局命名空间来模仿他们的作弊。

template<class T, std::enable_if_t<std::is_same<T,void>{}, bool>>
void get(int)=delete;

应该激活“解析得到模板”。

您无需执行此操作即可使结构化绑定正常工作。如上所述,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;
}
© www.soinside.com 2019 - 2024. All rights reserved.