テンプレートパラメータをタグディスパッチの入力として用いてメタプログラミングを実現する方法?
下記のような実装を持たない関数プロトタイプがあるとします。
struct tag1{};
struct tag2{};
// function declaration
std::true_type has_hoge(tag1);
std::false_type has_hoge(tag2);
また、下記のようなboolの型がtrueの場合は整数型を符号ありに、falseの場合は整数型の符号を外すconvertクラスを考えます。
template<bool cond, typename int_type>
struct convert;
template<typename int_type>
struct convert<true, int_type>
{
typedef typename std::make_signed<int_type>::type type;
};
template<typename int_type>
struct convert<false, int_type>
{
typedef typename std::make_unsigned<int_type>::type type;
};
このconvertとhas_hogeのtag dispatchを用いると下記のように書くことができます。
// int
convert<decltype(has_hoge(tag1()))::type::value, int>::type int_hoge;
// unsigned int
convert<decltype(has_hoge(tag2()))::type::value, int>::type uint_hoge;
このtag1およびtag2の部分をテンプレートにしたいのですが、エラーとなってしまいます。
/* コンパイルエラーになる。
template<typename tag, typename int_type>
struct hogehoge
{
typedef typename convert<decltype(has_hoge(tag()))::type::value, int_type>::type type;
};
*/
テンプレートはテンプレート引数が与えられるまでは実態化されないため、上記のコードは問題ないと思うのですがエラーとなります。
どのようにしたらエラーを回避できるでしょうか?
環境はvisual studio 2015 professionalです。
追記
回答をいただいたworkaroundを追加した例です。
#include<type_traits>
#include<iostream>
struct tag1{};
struct tag2{};
// function declaration
static std::true_type has_hoge(tag1);
static std::false_type has_hoge(tag2);
template<bool cond, typename int_type>
struct convert;
template<typename int_type>
struct convert<true, int_type>
{
typedef typename std::make_signed<int_type>::type type;
};
template<typename int_type>
struct convert<false, int_type>
{
typedef typename std::make_unsigned<int_type>::type type;
};
template<typename tag, typename int_type>
struct result
{
private:
typedef typename decltype(has_hoge(tag())) _type;
public:
typedef typename convert<_type::type::value, int_type>::type type;
};
int main()
{
std::cout << typeid(result<tag1, int>::type).name() << std::endl;
std::cout << typeid(result<tag2, int>::type).name() << std::endl;
return 0;
}