Alias template specialisation
Asked Answered
H

4

45

Can alias templates (14.5.7) be explicitly specialised (14.7.3)?

My standard-fu fails me, and I can't find a compiler to test on.

The text "when a template-id refers to the specialization of an alias template" implies yes, but then the example appears to refer to something else, implying no.

NB. I'm working from n3242, one behind the FDIS, in which the title of this section is "Aliase templates". Lol.

Hedgerow answered 8/7, 2011 at 9:25 Comment(4)
For the general public information, I would like to mention that clang supports alias templates.Beore
@Johannes: Version information please :)Hedgerow
@Johannes: Ah yes, I read that before once ;)Hedgerow
As this question is a bit old this may be irrelevant but alias declarations work in gcc 4.7.3.Helper
B
38

What the Standard means by "specialization" is the transformation of a generic template to a more specialized entity. For example, instantiating a non-member class template yields a class that's not a template anymore. The term "specialization" is two fold, and can refer to a generated specialization (which is a specialization that was instantiated, possibly from a partial specialization) and to an explicit specialization (which is what you referred to).

Alias templates aren't instantiated and there aren't specializations of them. There is nothing they could instantiate to. Instead, whenever their name is followed by a template argument list, the type denoted is the type you get by replacing the name and argument list by the alias'ed type, replacing all template parameter references with the arguments given in the argument list. That is, rather than the specialization of it being an alias, the alias template itself serves as an alias, without the need to instantiate anything. This replacement is done very early. Consider:

template<typename T> using ref = T&;
template<typename T> void f(ref<T> x) { x = 10; }
int main() { int a; f(a); return a; /* 10 */ }

The replacement is done at the time ref<T> is named (such a names are used to refer to class or function template specializations; hence the spec describes such names to "refer to the specialization of an alias template"). That is, the parameter of f has type T&, and thus, T can be deduced. This property is preventing explicit or partial specializations of alias templates. Because in order to pick the correct specialization of ref, it needs to know T. But to know it, it needs to compare ref<T> against the argument type to deduce T. It's summarized in the paper N1406, "Proposed addition to C++: Typedef Templates", section 2.2

2.2 The Main Choice: Specialization vs. Everything Else

After discussion on the reflectors and in the Evolution WG, it turns out that we have to choose between two mutually exclusive models:

  1. A typedef template is not itself an alias; only the (possibly-specialized) instantiations of the typedef template are aliases. This choice allows us to have specialization of typedef templates.

  2. A typedef template is itself an alias; it cannot be specialized. This choice would allow:

    • deduction on typedef template function parameters (see 2.4)
    • a declaration expressed using typedef templates be the same as the declaration without typedef templates (see 2.5)
    • typedef templates to match template template parameters (see 2.6)

It should be noted that the quoted paper, which favors option 1, did not make it into C++0x.


EDIT: Because you desperately want to have a spec quote saying so explicitly. 14.5p3 is one that does

Because an alias-declaration cannot declare a template-id, it is not possible to partially or explicitly specialize an alias template.

Beore answered 8/7, 2011 at 10:19 Comment(3)
Wow, this kills most of my anticipated uses for template aliases. I was looking forward to getting rid of structs that serve no purpose other than to hold a typedef.Fastening
@JosephGarvin, Is this correct then? Does one has to fallback to the old struct ways of defining template typedef?Borne
@alfc: Only if you want to specialize the typedef. I realized later this isn't so bad -- you can have a template alias of a template that is specialized. Only the alias itself can't be specialized, which in practice is not desired as often.Fastening
O
10

If you need pointwise mapping from something to types, this works(in gcc 4.8.3):

//  int to type mapper
template<int BITS>
struct BitsToTypesMap
{
    typedef void TYPE;  //  default
};

//  pointwise mapping 
template<>
struct BitsToTypesMap<32>{  typedef int TYPE;   };
template<>
struct BitsToTypesMap<8>{   typedef char TYPE;  };
template<>
struct BitsToTypesMap<16>{  typedef short TYPE; };

//  cute wrapping
template<int BITS> using MyScalarType = typename BitsToTypesMap<BITS>::TYPE;

//  TEST
template<int BITS>
MyScalarType<BITS>
Add ( MyScalarType<BITS> x, MyScalarType<BITS> y )
{
    return x+y;
}

int
test()
{
    MyScalarType<32> i=Add<32>(1,2);
    MyScalarType<8 > b=Add<8 >(1,2);
    MyScalarType<16> s=Add<16>(1,2);
    return i+b+s;
}
Oaks answered 12/4, 2018 at 9:41 Comment(0)
H
8

Bjarne says:

Specialization works (you can alias a set of specializations but you cannot specialize an alias)

And, whilst not an explicit rule, "alias templates" are missing from the following list at 14.7.3/1:

An explicit specialization of any of the following:

  • function template
  • class template
  • member function of a class template
  • static data member of a class template
  • member class of a class template
  • member class template of a class or class template
  • member function template of a class or class template

can be declared[...]

I think that this is the best guarantee you'll get.

Hedgerow answered 8/7, 2011 at 9:28 Comment(7)
Care to post some nice examples? I want to copy/paste and test some compilers. I believe GCC 4.4 has no support at all, and I don't know about 4.6.1 now...Augustinaaugustine
@Kerrek: I never got around to making any. :)Hedgerow
template <typename T, int N> struct A { static const int value = N; }; template <typename T> using V = A<T, 42>; template <> using V<int> = A<42, 48>; int main() { std::cout << V<char>::value << ", " << V<int>::value; }, I guess.Hedgerow
Sadly no support for template aliases even in GCC 4.6.1 :-(Augustinaaugustine
@Tomalak Geret'kal : Your code and clang trunk : "error : explicit specialization of alias templates is not permitted"Smasher
@Borne next time you might want to add more explantion as to why you updated the link when you suggest an edit like that. It was a valid edit, but I almost rejected it because it seemed like you were changing the link completely to a different site for no reasonParedes
Here is a simple example: template <typename T> using ContainerT = std::vector<T>; using ContainerIntT = ContainerT<int>;Needlefish
B
7

I am not sure if I understand the question, but in any case I tried to simulate specialization of alias template.

I assume that the idea is to restrict the alias template to certain (pattern matched type); something that we used to do with this sort of code:

template<class Vector> struct old_style;
template<class T> struct old_style<std::vector<T> >{
   typedef typename std::vector<T>::value_type type;
};

(this is just an example, there are other way to extract the value_type of a generic std::vector).

Now to the aliases:

template<class Vector> using new_style = typename Vector::value_type;

It does the same work, but this does not replace old_stype<...>::type, since it is not as restrictive. The first try to have a perfect alias replacement is this hypothetical code:

//template<class Vector> using new_style2; // error already here
//template<class T> using new_style2<std::vector<T> > = typename Vector::value_type;

Unfortunately it doesn't compile (in theory because of nominal reasons stated in other answers and in the standard, in practice I guess there is no fundamental reason for this to be a limitation). Fortunately one can fallback to the old fashioned struct::type way of doing it an only use the new alias template feature to forward the work,

template<class Vector> struct new_style2_aux;
template<class T> struct new_style2_aux<std::vector<T> >{
   typedef typename std::vector<T>::value_type type;
};
template<class Vector> using new_style2 = typename new_style2_aux<Vector>::type;

One can make it automatic with a define

#define SPECIALIZED_ALIAS_TEMPLATE(NamE, Pattern_arG, PatterN_expR, DefinitioN) \
template<class> struct NamE ## _aux; \
template<Pattern_arG> struct NamE ## _aux<PatterN_expR>{ \
    typedef DefinitioN type; \
}; \
template<class NamE ## _dummy> using NamE = typename NamE ## _aux< NamE ## _dummy >::type; 

Which can be used as:

SPECIALIZED_ALIAS_TEMPLATE(new_style3, class T, std::vector<T>, typename std::vector<T>::value_type);

If one needs an arbitrary number of specializations (or non local in the code), one has to use a more complicated define in two parts, one for declaring and one for specializing (as it should be):

#define DECLARE_ALIAS_TEMPLATE(NamE)\
template<class> struct NamE ## _aux;\
template<class NamE ## _dummy> using NamE = typename NamE ## _aux< NamE ## _dummy >::type; 

#define SPECIALIZE_ALIAS_TEMPLATE(NamE, Pattern_arG, PatterN_expR, DefinitioN)\
template<Pattern_arG> struct NamE ## _aux<PatterN_expR>{ \
    typedef DefinitioN type; \
};

Used as follows:

DECLARE_ALIAS_TEMPLATE(new_style4);

SPECIALIZE_ALIAS_TEMPLATE(new_style4, class T, std::vector<T>, typename std::vector<T>::value_type);
SPECIALIZE_ALIAS_TEMPLATE(new_style4, class T, std::set<T>, typename std::set<T>::value_type);

All the code above can be copied and pasted to test:

#include<vector>
#include<map>
// ... paste code above //
int main(){
    old_style<std::vector<double> >::type a; // is a double
//  old_style<std::set<double> >::type a; // error (should work only for std::vector)
    new_style2<std::vector<double> > b; // is double
//  new_style2<std::set<double> > c; // error (should work only for std::vector)
    new_style3<std::vector<double> > d; // is double
//  new_style3<std::set<double> > d; // error (should work only for std::vector)
    new_style4<std::vector<double> > e; // is double
    new_style4<std::set<double> > f; // is double, this is another specialization
    return 0;
}

Sorry if this is not what you are looking for. I believe it can be used with variadic templates, and with extra template arguments (in the specialization) but didn't test it.

Improvements are very welcomed.

Borne answered 27/12, 2012 at 6:48 Comment(2)
Hah, +1 cos this is quite nice. It's ultimately just a preprocessor wrapper for specialising structs, though.Hedgerow
@LightnessRacesinOrbit, yes but there is no ::type at the end of the alias name.Borne

© 2022 - 2024 — McMap. All rights reserved.