今日のテーマは、Visual C++だけでコンパイル・実行できる不思議なコードです。(nullptrさえ直せば)2005から2013までいずれでも通用します。

#include <iostream>
 
void f() { std::cout << "f" << std::endl; }
void g() { std::cout << "g" << std::endl; }
 
template<class T>
class TypeF
{
  friend void InvokeImpl(T*)
  {
    f();
  }
};
 
template<class T>
class TypeG
{
  friend void InvokeImpl(T*)
  {
    g();
  }
};
 
template<class T>
class Selector
{
  friend void InvokeImpl(T*);
 
public:
  static void Invoke()
  {
    return InvokeImpl(static_cast<T*>(nullptr));
  }
};
 
// ここから利用例
 
struct Hoge;
struct Piyo;
struct Fuga;
 
template class TypeF<Hoge>;
template class TypeG<Piyo>;
template class TypeF<Fuga>;
 
int main()
{
  Selector<Hoge>::Invoke();
  Selector<Piyo>::Invoke();
  Selector<Fuga>::Invoke();
}

これを実行するとこういう出力になります。

f
g
f

このコードは「型によって関数fとgを呼び分ける」というものです。

利用者は、自分の作った型を実引数にTypeFまたはTypeGを明示的実体化します。Selector::Invokeに型を与えて呼び出すと、明示的実体化したほうのInvokeImplが呼び出されるというからくりです。このtemplateとfriendの組み合わせ方がGCCやClangではうまくいきませんでした。

これに相当することをやるだけなら、ほかにやりよう(GCCでもClangでもできる方法)はあります。単にこういう方法もあるという紹介でした。

スポンサード リンク

この記事のカテゴリ

  • ⇒ friendとtemplateによるVisual C++でしか動かないコード
  • ⇒ friendとtemplateによるVisual C++でしか動かないコード