ゆとりーなの日記

日記的な事を書いて行くと思はれる

テンプレートfriendが地雷

昨日辺りにtwitterを見てて思ったことをさらっとメモしておきます。
こういうコードがあるとコンパイルエラーになるってのがあります。

template <typename T>
struct Hoge {
  Hoge() = default;

  template <typename U>
  Hoge(const Hoge<U> &rhs) : hoge(rhs.hoge) {}

 private:
  T hoge = 0;
};

int main() {
  Hoge<int> hi;
  Hoge<double> hd = hi; // privateをいぢっちゃダメ!
  return 0;
}

HogeHogeは別の型なのでテンプレートコピーコンストラクタの部分でprivateに引っかかります。これでは納得が行かないのでなんとかしようとするわけです。

template <typename T>
struct Hoge {
  Hoge() = default;

  template <typename U>
  Hoge(const Hoge<U> &rhs) : hoge(rhs.hoge) {}

 private:
  // 甘え
  template <typename U>
  friend class Hoge;

  T hoge = 0;
};

int main() {
  Hoge<int> hi;
  Hoge<double> hd = hi;
  return 0;
}

テンプレートフレンドクラスに甘えると通せます。しかしおそらく多分これは地雷で、

template <typename T>
struct Hoge {
  Hoge() = default;

  template <typename U>
  Hoge(const Hoge<U> &rhs) : hoge(rhs.hoge) {}

 private:
  template <typename U>
  friend class Hoge;

  T hoge = 0;
};

// 悪さ
template <>
struct Hoge<void> {
  template <typename T>
  static T &warusa(Hoge<T> &t) {
    return t.hoge;
  }
};

#include <iostream>

int main() {
  Hoge<int> hi;
  Hoge<double> hd = hi;
  Hoge<void>::warusa(hd) = 313;
  std::cout << Hoge<void>::warusa(hd) << std::endl;
  return 0;
}

こういう悪さをするとあっさりカプセル化をぶっ壊すことが出来るのでした。