【追記】不可能な内容かも知れないのですが、まだ少しだけ希望を持っていますので、「解決済」には致しません。もし、解をお持ちの方がいらっしゃいましたら、是非ご教授下さい。
【2016/12/22追記】
長らく放置してしまいました。断念したのでクローズします。
今、あるライブラリをC++11準拠の条件で開発してます。
コンパイラは、msvc 2015とg++4.9.2以降を想定しています。
イメージ的には、下記のlib.hを開発してユーザさんへ提供し、ユーザさんがmain.cppを開発します。
Client()関数の中身が結構大きくなりそうなので、できればClient()関数をテンプレートではなく通常の関数にしたいのです。
このような場合、通常はLib<>クラスを基底クラスから派生するようにし、Func()関数を仮想関数にすると思います。しかし、関数テンプレートを仮想関数にすることができませんので、Client()を非テンプレート化できないのです。
仮想関数に代わる何か良い方法はないでしょうか?
Typeには制限を付けられませんが、valueはあまり無茶に増えることはないので、現時点ではClient()を関数テンプレートのままとし、使用するvalueについて明示的実体化することで考えています。
しかし、もし、方法があればClient()を通常の関数で開発できるようにしたいのです。
現時点では無理でも、C++14やC++17等で対応できる可能性があればその情報を頂けるとありがたいです。
C++
1// lib.h 2#include <iostream> 3#include <typeinfo> 4 5template<int value> 6struct Lib 7{ 8 template<typename Type> 9 void Func(const Type& aInstance) 10 { 11 std::cout << value << " :" << typeid(aInstance).name() << "\n"; 12 // 実際にはここで下記シングルトンを生成しています 13 // template<typename Type, int value> 14 // class Singleton {}; 15 } 16};
C++
1// main.cpp 2#include "lib.h" 3 4class Foo {}; 5 6template<int value> 7void Client(Lib<value>* aLib) 8{ 9 aLib->Func(123); 10 aLib->Func(123.0); 11 aLib->Func(Foo()); 12} 13 14int main() 15{ 16 Lib<456> lib_456; 17 Lib<789> lib_789; 18 19 Client(&lib_456); 20 Client(&lib_789); 21}
【追記】
サンプルの説明が不適切だったので、Func()内のコメントを修正しました。
また、何のためにSingleton<Type, value>を作っているのか分からないと思います。
かなり長くなってしまうのですか、実際に使っているものに近いサンプルを以下に示します。
boostで使われているテクニックですが、シングルトン生成時、スタティック変数Instanceをこのように初期化することで、main()関数が走る前にこのシングルトンが生成されます。
これにより、Lib<>のコンストラクタで、Lib<>::Func()に渡されるTypeの型リストへアクセスできるようになるのです。
このタイミングではLib<>がコンストラクトされていないので、動的な方法ではvalueをリストできないのです。
こんなに複雑なことをしている目的は、Lib<>のインスタンスで使われているTypeのリストをvalueと関連づけて、Lib<>のコンストラクタ内で取り出せるようにすることです。
C++
1// lib.h 2#include <iostream> 3#include <typeinfo> 4#include <vector> 5 6class BaseSingleton; 7std::vector<BaseSingleton*> TypeList; 8 9class BaseSingleton 10{ 11public: 12 virtual void print(int aValue) = 0; 13}; 14 15template<typename Type, int value> 16class Singleton : public BaseSingleton 17{ 18private: 19 static Singleton& Instance; 20 Singleton() 21 { 22 std::cout << "Singleton() : " << value << " :" << typeid(Type).name() << "\n"; 23 } 24 static void use(const Singleton&) {} 25 26public: 27 static Singleton& getInstance() 28 { 29 static Singleton instance; 30 use(Instance); 31 TypeList.push_back(&instance); 32 return instance; 33 } 34 35 void print(int aValue) 36 { 37 if (aValue == value) 38 std::cout << "print() : " << value << " :" << typeid(Type).name() << "\n"; 39 } 40 41 // コピー/ムーブ禁止 42 Singleton(const Singleton&) = delete; 43 Singleton( Singleton&&) = delete; 44 Singleton& operator=(const Singleton&) = delete; 45 Singleton& operator=( Singleton&&) = delete; 46}; 47template<typename Type, int value> 48Singleton<Type, value>& Singleton<Type, value>::Instance = Singleton<Type, value>::getInstance(); 49 50template<int value> 51struct Lib 52{ 53 Lib() 54 { 55 // ここで自分で使われている型のリストを抽出してます 56 for (auto& itr : TypeList) { 57 itr->print(value); 58 } 59 } 60 61 template<typename Type> 62 void Func(const Type& aInstance) 63 { 64 Singleton<Type, value>::getInstance(); 65 66 // 他にSFINAEを使ってTypeで分岐し、下記のようなイメージの処理をします 67 // 組み込み型の時は特定の処理を行う 68 // 関数bar()を持つclassなら、bar()を呼ぶ 69 // 関数boo()を持つclassなら、boo()を呼ぶ 70 // それ以外なら、static_assert(false)する 71 } 72};
C++
1// main.cpp 2#include "lib.h" 3 4class Foo {}; 5template<int value> 6void Client(Lib<value>* aLib) 7{ 8 aLib->Func(123); 9 aLib->Func(123.0); 10 aLib->Func(Foo()); 11} 12 13class Bar {}; 14template<int value> 15void Client2(Lib<value>* aLib) 16{ 17 aLib->Func("string"); 18 aLib->Func(Bar()); 19} 20 21int main() 22{ 23 std::cout << "---------- Start main()\n"; 24 25 std::cout << "pre Lib<456>\n"; 26 Lib<456> lib_456; 27 std::cout << "post Lib<456>\n"; 28 Client(&lib_456); 29 30 std::cout << "pre Lib<789>\n"; 31 Lib<789> lib_789; 32 std::cout << "post Lib<789>\n"; 33 Client(&lib_789); 34 35 std::cout << "pre Lib<-123>\n"; 36 Lib<-123> lib_m123; 37 std::cout << "post Lib<-123>\n"; 38 Client2(&lib_m123); 39}
msvc2015での実行結果は下記の通りです。
Singleton() : 456 :int
Singleton() : 456 :double
Singleton() : 456 :class Foo
Singleton() : 789 :int
Singleton() : 789 :double
Singleton() : 789 :class Foo
Singleton() : -123 :char [7]
Singleton() : -123 :class Bar
---------- Start main()
pre Lib<456>
print() : 456 :int
print() : 456 :double
print() : 456 :class Foo
post Lib<456>
pre Lib<789>
print() : 789 :int
print() : 789 :double
print() : 789 :class Foo
post Lib<789>
pre Lib<-123>
print() : -123 :char [7]
print() : -123 :class Bar
post Lib<-123>

回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。