Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ error distinguishing specialization when passing a const array

consider the code

     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&>{};

The following template instantiations work fine:

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

but the following one doesn't work:

     A<const int[3]>

Is there some reason that this particular combination is invalid or is it perhaps a bug with g++4.6.3?

By the way I managed to get around this using SFINAE and boost::disable_if<>, so at least the problem is solved.

EDIT

I forgot to mention that the error in question is an ambiguous class template instantiation and it couldn't decide between the overload for const or the overload for an array.

EDIT2

This has nothing to do with pointers, here's the full context:

I'm going through the book C++ Template Metaprogramming and am doing question 2-3 (Chapter 2 question 3) which says:

Use the type traits facilities to implement a type_descriptor class template, whose instances, when streamed, print the type of their template parameters: NOTE: we cannot use RTTI to the same effect since, according to 18.5.1 [lib.type.info] paragraph 7 of the standard, typeid(T).name() is not guaranteed to return a meaningful result.

My solution (including the the workaround for the compilation error) is as follows:

    //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

Sample usage is:

      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;

and the corresponding output is (when the workaround is in, otherwise it doesn't compile on that last one):

int *

int * [3]

Unknown *

int const &

int const * const &

int [4]

int (*)()

int * & (*)(Unknown const &)

int * &

int []

long const []

So C++ is able to differentiate pointers and arrays for the template parameters, is able to correctly, recursively, separate compound types and output the correct result, except for const A[]. It needs help with that one

like image 624
SirGuy Avatar asked Nov 13 '22 20:11

SirGuy


1 Answers

An array type with a const element type is both a const qualified type (the const applies bidirectionally) and an array type.

So you should fix the specializations.

like image 184
Johannes Schaub - litb Avatar answered Nov 15 '22 12:11

Johannes Schaub - litb