在类上启用std::get支持

Enable std::get support on class

本文关键字:get 支持 std 启用      更新时间:2023-10-16

我必须特化哪些模板来支持std::get?

struct MyClass {
  int a;
};
template <const size_t I>
struct MyContainer {
  MyClass array[I];
};

我要专门化什么才能做:

MyContainer<16> mc;
std::get<0>(mc);

std::get不是标准库的自定义点;三个函数模板重载(对于pair, tuplearray)不明确地允许用户定义的重载,因此17.6.4.2.1p1适用,并且添加自己的函数模板重载声明是未定义的行为。

注意get作为非限定的名称在c++ 17中是自定义点;结构化绑定声明协议使用它来访问类元组元素;但这是一个非限定名,而不是限定名std::get

也就是说,如果你写:

namespace std {
   template<size_t I, size_t N> MyClass &get(MyContainer<N> &c) { return c.array[I]; }
}

和类似的右值引用和const引用重载,您的程序可能会像您期望的那样工作。

然而,由于标准已经提供了array:

,所以没有什么意义。
template<size_t N> using MyContainer = std::array<MyClass, N>;

我猜你想实现一些算法,需要访问任意数组类容器使用编译时索引,因此目的是使用一些函数(如std::get)来统一执行该任务?!在这种情况下,它与使beginend对您的类可用是相同的业务。您只需在您声明容器类的名称空间中声明一个函数get,并让ADL完成它的工作。

    template <unsigned I, unsigned N>
    MyClass& get (MyContainer<N>& c) { return c.array[I]; }
    template <unsigned I, unsigned N>
    MyClass const& get (MyContainer<N> const& c) { return c.array[I]; }

在你的算法中,你只使用get(没有std命名空间前缀),ADL将调用正确的函数。因此,对于array, tuplepair等标准结构,std::get被调用,而对于您提供的容器,get函数被调用。

    int main(){
        std::array<int, 3> a {{0,1,2}};
        auto t = std::make_tuple(0.0, 1.0f, 2);
        auto p = std::make_pair('0', 4.4);
        MyContainer<3> c;
        std::cout << get<1>(a) << std::endl;
        std::cout << get<1>(t) << std::endl;
        std::cout << get<1>(p) << std::endl;
        std::cout << get<1>(c).a << std::endl;
        return 0;
    }
示例