プロが教えるわが家の防犯対策術!

c++11言語でのテンプレート部分特殊化についての質問です。

コメントアウト部分は出力結果です

template<class T> struct VT { static const int type = 1;};
template<class T,int N> struct VT< T[N] > { static const int type = 2;};
template<class T,int N> struct VT< const T[N] > { static const int type = 3;};
template<class T> struct VT< T* > { static const int type = 4;};
template<class T> struct VT< const T*const > { static const int type = 5;};
#include<iostream>
#include<typeinfo>
int main(){
std::cout<<"A:"<< VT< char >::type << std::endl; // A:1
std::cout<<"B:"<< VT< char[10] >::type << std::endl; // B:2
std::cout<<"C:"<< VT< char* >::type << std::endl; // C:4
std::cout<<"D:"<< VT< char const [1] >::type << std::endl; // D:3
std::cout<<"E:"<< VT< decltype("") >::type << std::endl; // E:1
std::cout<<"G:"<< typeid( char const [1] ).name() << std::endl;// G:char const [1]
std::cout<<"H:"<< typeid( "" ).name() << std::endl;// H:char const [1]
}

型名を直接記述したD,G、文字列リテラルを記述したE,H。
コンパイラ毎の差はあれど、GとHの型名は同じものが表示されます。
ですが、[D:3] [E:1]と値は違い、別の特殊化テンプレートが使われています。
この部分が分かりません。

また、配列リテラル、文字列リテラルに対し部分特殊化テンプレートを宣言する方法などありましたら、ご教示お願いします。

A 回答 (2件)

文字列リテラルが decltype で参照になるってことは, 参照に対する部分特殊化すればいい. 例えば


template <class T> struct VT<T &> { /* 省略 */ };
で参照に対する部分特殊化ができると思う. さらに配列に対しても部分特殊化したければ
template <class T, int N> struct VT<T (&)[N]> { /* 省略 */ };
とかでいいんじゃないかな.
    • good
    • 0
この回答へのお礼

返答ありがとうございます

VT<T &>
ただの参照型、失念していました。

VT<T (&)[N]>
試行錯誤の時、T[N]& などと記述しエラーが出ていたので不可能だと見誤っていました。
型表記への理解が甘いようです。

確認しました。
template<class T> struct VT { static const int type = 1;};
template<class T,int N> struct VT< T[N] > { static const int type = 2;};
template<class T,int N> struct VT< const T[N] > { static const int type = 4;};
template<class T> struct VT< T* > { static const int type = 3;};
template<class T> struct VT< T& > { static const int type = 9;};
template<class T> struct VT< T*&& > { static const int type = 7;};
template<class T> struct VT< T*& > { static const int type = 8;};
template<class T,int N> struct VT< T(&&)[N] > { static const int type = 10;};
template<class T,int N> struct VT< T(&)[N] > { static const int type = 11;};
#include<iostream>
int main(){
// 11
std::cout << VT< decltype("") >::type << std::endl;
}

お礼日時:2013/06/13 11:55

C++11 の規格そのものは確認してませんが (手元には N3242 しかない), 文字列リテラルは左辺値となっています. で decltype は左辺値に対して「なんかへの参照」を返すので, decltype("") は const char (&) [1] かなんかになってるんじゃないでしょうか.



で typeid では参照が消えるルールになってるので const char [1] になっちゃってる, と.
    • good
    • 0
この回答へのお礼

typeidも一般関数と同じ扱いで渡されているということですか。
てっきり特別扱いされていると思っていました。
(環境毎のデバッグ関数ならば判断できるものがあるようです)
ありがとうございます。

<boost/type_traits.hpp>のis_*<T>::valueを総当たりで調べた所、
指摘された通りdecltype("")とchar const *&の結果が一致しました。

以下、自分の理解状況です。

boostを信頼すると
false:boost::is_array< decltype("") >::value
true :boost::is_array< char const [1] >::value

true :boost::is_reference< decltype("")::value
false:boost::is_reference< char const [1] >::value

false:boost::is_object< decltype("") >::value
true :boost::is_object<char const [1]>::value
と、decltype("")は参照型(&)であり、

◆template特殊化では、参照型(&)は配列([N])型扱いも、ポインタ(*)型扱いもされません
(のようです)

そこでboost::is_referenceから参照型特殊化の方法を読んでいるところなのですが、
どうにも入り組んでおり、難航しています

お礼日時:2013/06/13 09:14

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!