views:

408

answers:

2

I have a metafunction:

struct METAFUNCION
{
  template<class T>
  struct apply
  {
    typedef T type;
  };
};

Then I define a helper:

template<class T1, class T2>
struct HELPER
{
};

And then I have second metafunction which derives from the METAFUNCTION above and defines partial specialization of apply struct:

struct METAFUNCION2 : METAFUNCION
{
  template<class T1, class T2>
  struct apply<HELPER<T1, T2> > : METAFUNCION::apply<T2>
  {
  };
};

So far, so good - the code compiles under g++ 4.3.2. So I used it like below:

#include <typeinfo>
#include <string>
#include <cstdlib>
#include <cxxabi.h>

template<typename T>
struct type_info2
{
  static std::string name()
  {
    char *p = abi::__cxa_demangle(typeid(T).name(), 0, 0, 0);
    std::string r(p);
    free(p);
    return(r);
  }
};

#include <boost/mpl/apply.hpp>
#include <iostream>

int main()
{
  std::cout <<
    type_info2<boost::mpl::apply<METAFUNCION, int>::type>::name() <<
    std::endl;
  std::cout <<
    type_info2<boost::mpl::apply<METAFUNCION, HELPER<float, double> >::type>::name() <<
    std::endl;
  std::cout <<
    type_info2<boost::mpl::apply<METAFUNCION2, HELPER<float, double> >::type>::name() <<
    std::endl;
  return(0);
}

The output:

int
double
double

That surprised me a bit as I expected:

int
HELPER<float, double>
double

Now, I know that code like above does not compile under Microsoft Visual C++ 2008 (I don't remeber the message but it was something along the lines that I cannot specialize apply struct inside METAFUNCTION2 struct).

So my question is - is this g++ behaviour conformant with the standard? I have a strong feeling that there is something wrong here but I am not 100% sure.


For the curious - I have the behaviuor as I expected when I redefine METAFUNCTION2 this way:

struct METAFUNCION2 : METAFUNCION
{
  template<class T>
  struct apply : METAFUNCION::apply<T>
  {
  };
  template<class T1, class T2>
  struct apply<HELPER<T1, T2> > : METAFUNCION::apply<T2>
  {
  };
};
A: 

The following code is illegal:

struct METAFUNCION2 : METAFUNCION
{
  template<class T1, class T2>
  struct apply<HELPER<T1, T2> > : METAFUNCION::apply<T2>
  {
  };
};

According to C++ Standard 14.7.3/3:

A declaration of a function template or class template being explicitly specialized shall be in scope at the point of declaration of an explicit specialization.

EDIT: According to Core Issue 727 this restriction does not apply to partial specializations of member templates.

Kirill V. Lyadvinsky
Well it still is not clear if it should be possible to specialize inner template of base class in its derivative and if it should then be visible in derived class only or base class as well.
Tomek
A: 

So I filed a bug on gcc

Tomek
I believe your Standard quote doesn't apply though, because you are not declaring an explicit specialization (you are declaring and defining a partial specialization instead), and because the declaration of the class template being specialized *is* in scope already. I haven't found a clearly spelled out requirement that the partial specialization of a member template should be a member of the same class, though.
Johannes Schaub - litb
Well, VC++ rejects the code so at least there is something to think about. And as I wrote - I wouldn't expect partial specialization to work up the inheritance tree. At least this is what I though when I "invented" that code.
Tomek
@Tomek, same suspicion here :) I neither think that partial specialization should work up the tree. Both the primary and the partial specialization templates are "alternative definitions" (original wording) for the same template, so they should provide definitions for the template in the same class scope, not in the derived class scope (which would mean the definition occurs for another scope than the declaration of the template). But i would have liked an explicit quote about that in the standard.
Johannes Schaub - litb
For the followers I've just got an email from gcc bugzilla that this bug is fixed in gcc 4.5.0.
Tomek