先上代码,注意 get 函数和其友元函数
#include <utility>
#include <type_traits>
template <unsigned Height, typename T, bool = std::is_class_v<T> && !std::is_final_v<T>>
class TupleElt;
template <unsigned Height, typename T>
class TupleElt<Height, T, false>
{
private:
T value;
public:
TupleElt() = default;
template <typename U>
TupleElt(U &&other) : value(std::forward<U>(other)) {}
T &get() { return value; }
T const &get() const { return value; }
};
template <unsigned Height, typename T>
class TupleElt<Height, T, true> : private T
{
public:
TupleElt() = default;
template <typename U>
TupleElt(U &&other) : T(std::forward<U>(other)) {}
T &get() { return *this; }
T const &get() const { return *this; }
};
template <unsigned H, typename T>
T &getHeight(TupleElt<H, T> &te)
{
return te.get();
}
template <typename... Types>
class Tuple;
template <unsigned I, typename... Elements>
auto get(Tuple<Elements...> &t) -> decltype(getHeight<sizeof...(Elements) - I - 1>(t))
{
return getHeight<sizeof...(Elements) - I - 1>(t);
}
template <typename... Types>
class Tuple;
template <typename Head, typename... Tail>
class Tuple<Head, Tail...> : private TupleElt<sizeof...(Tail), Head>, private Tuple<Tail...>
{
template <unsigned I, typename... Elements>
friend auto get(Tuple<Elements...> &t) -> decltype(getHeight<sizeof...(Elements) - I - 1>(t)); \\ 友元函数声明
private:
using HeadElt = TupleElt<sizeof...(Tail), Head>;
public:
Head &getHead() { return static_cast<HeadElt *>(this)->get(); }
Head const &getHead() const { return static_cast<HeadElt const *>(this)->get(); }
Tuple<Tail...> &getTail() { return *this; }
Tuple<Tail...> const &getTail() const { return *this; }
};
template <>
class Tuple<>
{
};
int main()
{
Tuple<char, char> t1;
get<0>(t1);
return 0
}
我跟着 C++ templates 2nd edition, 实现了一个简单的 tuple 类和 get 函数,其中 tuple 类里面的元素被 tuple 类私有继承,get 函数通过计算元素高度,来实现直接从派生类到基类的转换来访问对应的元素,由于 tupleElt 类被私有继承,get 函数必须在 tuple 类中被声明为友元函数才可以被访问(上述代码注释处)但是即使被声明为了友元函数,gcc 还是提示 get 函数无法访问 tuple 的基类,导致编译错误,但 MSVC 可以顺利编译通过,是为什么呢,如果有错误该怎么改?