2017-02-23 22 views
6

現在、テンプレートの汎用タイプを文字列リテラルと同様にstd::stingに制限する方法について考えています。したがって、私は推測された型をstd::is_sameを使って目的の型と比較します。 std::stringの場合はすぐに動作します。 char const配列を意味する文字列リテラルでは、型にstd::decayを使用し、その結果を型char const *と比較した場合にのみ動作します。推測される型を私が思うものと直接比較すると、is_sameは、次のコード例に示すようにfalseを返します。テンプレート引数文字列からの引き出し

template <class TYPE> 
void function(TYPE&& parameter) 
{ 
    //this doesn't work as expected 
    std::cout << typeid(TYPE).name() << " : " << typeid(char const [5]).name() << std::endl; 
    std::cout << std::is_same<char const [5], TYPE>::value << std::endl; 
    //this works as expected 
    std::cout << typeid(std::decay_t<TYPE>).name() << " : " << typeid(char const *).name() << std::endl; 
    std::cout << std::is_same<char const *, std::decay_t<TYPE>>::value << std::endl; 
} 

int main(int argc, char** argv) 
{ 
    function("name"); 
    return 0; 
} 

生成される出力は以下の通りです:今

char const [5] : char const [5] 
0 
char const * __ptr64 : char const * __ptr64 
1 

、私は疑問に思ってすることは型が同一であるように見えるにもかかわらず、最初のケースでは、なぜis_sameリターンはfalseです。

私が思いつくことができる唯一の可能な説明は、std::is_sameのように、std::decayに似た変換が(関数呼び出しのような)型に適用されているということです。しかし、やはりこの変換はもう一方の型にも起こり、同じ結果をもたらし、その結果、等価になります。

+0

C++ 17まで待ってから、テンプレートを書いて 'std :: string_view'を使用してください。 –

+1

'TYPE'から参照を削除してみてください。文字列リテラルは左辺値です。 –

+0

ありがとうございます、あなたは正しいです。私はそれを知らなかった。行を 'std :: is_same > :: value'に変更すると、結果は等しくなります。文字列リテラルが左辺値とみなされるのはなぜですか?代わりにintリテラルであれば、それはrvalueと見なされますね。そして、これを受け入れられる答えにすることはできますか? – user1488118

答えて

6
template<class T, size_t size> 
struct array_t{}; 

    template <class T, size_t size> 
void function(T[size] parameter) { 
    std::cout << typeid(array_t<T, size>).name() << " : " << typeid(array_t<char, 5>).name() << std::endl; 
    std::cout << std::is_same<array_t<T, size>, array_t<char, 5>>::value << std::endl; 
}; 

文字列リテラルはchar const [N]として、しかしchar const (&)[N]として参照により値で渡されません。

これは私のために正しく動作:

1)のタイプの種類を表すstd::type_infoオブジェクトを参照しhereこと

std::cout << std::is_same<char const (&)[5], TYPE>::value << std::endl; 

注意。 typeが参照型である場合、結果は参照型を表すstd::type_infoオブジェクトを参照します。あなたは簡単に

std::is_same<int&, int>::value == false 

これはtypeid名前が同じである理由を説明するが、あなたのことをチェックすることにより、例えば、is_sametype_infoと同じように参照ネスを破棄していないことを確認することができます

is_sameテストは失敗します。

2

gccのカスタム関数の使用:

template < class T > 
constexpr std::string type_name() 
{ 
    std::string p = __PRETTY_FUNCTION__; 
    return p.substr(43 + 10, p.length() - 100 - 1 - 10); 
} 

そして、あなたのコードに追加:

std::cout << type_name<TYPE>() << " : " << type_name<char const [5]>() << std::endl; 

を結果は以下のとおりです。

A5_c : A5_c 
0 
const char (&)[5] : const char [5] 

は、だから、TYPEstd::remove_referenceを使用する必要があります。

+0

あなたは効果について正しいと思います。しかし、この原因はKerrek SBのコメントで言及されています。文字列リテラルは明らかに右辺値ではなく右辺値です。したがって、型は、転送参照パラメータを介して渡されるとき、 'T 'ではなく' T'として推論されます。 – user1488118

+0

@ user1488118あなたのコードで同じ文字列リテラルを使用すると、例えば '' string ''は別の場所で使用されますが、実際には同じ文字列です。これは毎回新しい一時的なものではありませんが、プログラムが実行されている間はメモリ内にとどまっていますので、参照するときは実際にはl値参照で参照してください。 – xinaiz

0

これは間違いの可能性があります。コンパイラは、コンパイル時にtypeidによって指定されたオブジェクトを生成します。コンパイラは各長さ(0〜2 ** n)の配列型をコンパイルしないので、必要に応じてコンパイルし、重複を「忘れる」ことがあります。特殊なテンプレートを使用して、含まれているタイプの長さを区切ります。これは型ではありませんが、他の型と等しいかどうかを調べることができます。

関連する問題