2012-10-17 2 views
5

コードC++エラーのconst配列を渡すとき

 template <class A> 
    class B; 

    template <class A> 
    class B<const A>{}; 

    template <class A, int N> 
    class B<A[N]>{}; 

    template <class A> 
    class B<A*>{}; 

    template <class A> 
    class B<A&>{}; 

次のテンプレートのインスタンス化が正常に動作考慮する:

 A<int*&> 
    A<const int*> 
    A<int*[3]> 

が、以下のいずれかが動作しません:

 A<const int[3]> 

この特定の組み合わせが無効である理由はありますか、おそらくg ++ 4.6のバグでしょうか.3?

私はSFINAEとboost :: disable_if <を使用してこの問題を回避することができましたが、少なくとも問題は解決されています。私は問題のエラーがあいまいなクラステンプレートのインスタンス化であり、それは、配列のためのconstのための過負荷や過負荷の間で決めることができなかったことを言及するのを忘れてしまった

EDIT

EDIT2

これは、ポインタとは何の関係もありません、ここで完全なコンテキストだ:

私は本C++テンプレートメタプログラミングを通じてつもりだと質問2-3(第2章をしています質問3):

type_descriptorクラステンプレートを実装するには、type_descriptorクラステンプレートを使用します。このテンプレートは、ストリーミングされたときにテンプレートパラメータのタイプを出力します。 注:使用できませんRTTIは、標準の18.5.1 [lib.type.info]パラグラフ7によると、意味のある結果を返すことは保証されていないので、同じ効果があります。

//QUESTION 2-3 
    template <class T, class enable = void> 
    struct type_descriptor 
    { 
     std::string operator()() const 
     { 
     return "Unknown"; 
     } 
    }; 

    //specializations for primitive types 
    #define TYPE_DESC_SPEC(type) template <> \ 
     struct type_descriptor<type,void>  \ 
     {std::string operator()() const{return #type;}}; 

    TYPE_DESC_SPEC(int) 
    TYPE_DESC_SPEC(long) 
    TYPE_DESC_SPEC(void) 
    TYPE_DESC_SPEC(short) 
    TYPE_DESC_SPEC(unsigned char) 
    TYPE_DESC_SPEC(unsigned short) 
    TYPE_DESC_SPEC(unsigned long) 

    //specializations for modifiers *, const, &, and [N] 

    template <class T> 
    struct type_descriptor<T&,void> 
    {std::string operator()(){return type_descriptor<T>()() + " &";}}; 

    template <class T> 
    struct type_descriptor<T*,void> 
    {std::string operator()(){return type_descriptor<T>()() + " *";}}; 

    //Replace void with what's in the comment for the workaround. 
    template <class T> 
    struct type_descriptor<const T, void/*typename boost::disable_if<boost::is_array<T> >::type*/> 
    {std::string operator()(){return type_descriptor<T>()() + " const";}}; 

    template <class T> 
    struct type_descriptor<T(*)(),void> 
    {std::string operator()(){return type_descriptor<T>()() + " (*)()";}}; 

    template <class T, class U> 
    struct type_descriptor<T(*)(U),void> 
    {std::string operator()(){return type_descriptor<T>()() + " (*)(" + type_descriptor<U>()() + ")";}}; 

    template <class T, int N> 
    struct type_descriptor<T[N],void> 
    { 
     std::string operator()() 
     { 
     std::stringstream s; 
     s << type_descriptor<T>()() << " [" << N << "]"; 
     return s.str(); 
     } 
    }; 

    template <class T> 
    struct type_descriptor<T[],void> 
    {std::string operator()(){return type_descriptor<T>()() + " []";}}; 

    //Now overload operator<< to allow streaming of this class directly 

    template <class T> 
    std::ostream & operator<<(std::ostream & s, type_descriptor<T> t) 
    { 
     return s << t(); 
    } 
    //END QUESTION 2-3 

使用例がある:回避策である場合(

 std::cout << "\nQuestion 2-3 results\n"; 
     std::cout << type_descriptor<int*>() << std::endl; 
     std::cout << type_descriptor<int*[3]>() << std::endl; 
     std::cout << type_descriptor<std::string*>() << std::endl; 
     std::cout << type_descriptor<const int&>() << std::endl; 
     std::cout << type_descriptor<const int *const&>() << std::endl; 
     std::cout << type_descriptor<int[4]>() << std::endl; 
     std::cout << type_descriptor<int(*)()>() << std::endl; 
     std::cout << type_descriptor<int*&(*)(const char &)>() << std::endl; 
     std::cout << type_descriptor<int*&>() << std::endl; 
     std::cout << type_descriptor<int[]>() << std::endl; 
     std::cout << type_descriptor<const long[]>() << std::endl; 

、対応する出力は、次のように(コンパイルエラーを回避を含む)

マイ溶液でありますそれ以外の場合は最後のコンパイルではコンパイルされません)。

 
int * 

int * [3] 

Unknown * 

int const & 

int const * const & 

int [4] 

int (*)() 

int * & (*)(Unknown const &) 

int * & 

int [] 

long const [] 

C++は異なることがありますテンプレートパラメータのポインタと配列は、複素数型を正しく、再帰的に分離して、const A[]以外の正しい結果を出力することができます。それは助けが必要です

+0

これで推測するつもりですが、 'const int [3]'が 'const int *'に崩壊すると思います。 –

+0

@AdrianCornishそれはそうではありません。編集を参照してください。それ以外にも、3番目の有効な例があれば、どちらもうまくいかないはずです。 – SirGuy

+0

'const int *'が 'int *'と異なっているため、3番目のコードは機能します.- –

答えて

1

const要素型の配列型はconst修飾型(constは双方向に適用されます)と配列型の両方です。

したがって、特殊化を修正する必要があります。

+0

配列やポインタや参照用ではないのはなぜですか? – SirGuy

+0

これはポインタにとって意味をなさないためです。ポインタはconstであり、constを指すことができます。また、間接参照である参照は概念的に2つの異なるconstを持つこともできますが、参照を異なるものを参照するように変更することはできないため、参照自体のconstは禁止されています。もう一方の側では、配列の値は、間接指定を行わずにすべての要素にすぎません。 constが双方向に適用されることは意味があります。 –

+0

'const int []'をconst intの配列と見なすことよりも、この定義に利点はありますか?上記のテンプレートの特殊化はあいまいではなく、配列の特殊化はインスタンス化されることになります。 – SirGuy

関連する問題