别名模板专门化

Alias template specialisation

本文关键字:专门化 别名      更新时间:2023-10-16

别名模板(14.5.7)可以显式特化(14.7.3)吗?

我的standard-fu失败了,我找不到一个编译器来测试。

文本"当template-id指的是别名模板的专门化时"暗示,但随后示例似乎指的是其他东西,暗示不是

<子> NB。我从n3242开始工作,一个在FDIS后面,其中本节的标题是"别名模板"。哈哈

标准中所谓的"专门化"是指将泛型模板转换为更专门化的实体。例如,实例化一个非成员类模板会产生一个不再是模板的类。术语"专门化"是双重的,可以指生成的专门化(这是一个实例化的专门化,可能来自部分专门化)和显式专门化(这就是您所引用的)。

别名模板没有实例化,也没有特殊化。没有它们可以实例化的对象。相反,只要它们的名称后面跟着模板实参列表,所表示的类型就是通过用别名类型替换名称和实参列表获得的类型,用实参列表中给出的实参替换所有模板形参引用。也就是说,别名模板本身不是作为别名的专门化,而是作为别名,而不需要实例化任何东西。这种替换很早就完成了。考虑:

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

替换是在命名ref<T>时完成的(这样的名称用于引用类或函数模板特化;因此,规范将这些名称描述为"引用别名模板的专门化")。也就是说,f的参数为T&型,由此可以推导出T。此属性防止别名模板的显式或部分专门化。因为为了选择ref的正确专门化,它需要知道T。但是要知道它,它需要将ref<T>与参数类型进行比较,从而推断出T。论文N1406,"对c++的建议添加:类型定义模板",2.2节

对此进行了总结。

2.2主要选择:专门化vs.其他一切

经过对反射器和Evolution WG的讨论,我们不得不在两个相互排斥的模型之间做出选择:

  1. typepedef模板本身不是别名;只有typedef模板的实例化(可能是专门化的)才是别名。

  2. 一个typedef模板本身就是一个别名;它不能专门化。这个选择允许:

    • typepedef模板函数参数的扣除(见2.4)
    • 使用typedef模板表示的声明与不使用typedef模板的声明相同typepedef模板(见2.5)
    • typepedef templates来匹配模板模板参数(见2.6)

应该注意的是,引用的论文支持选项1,并没有进入c++ 0x。


编辑:因为你迫切希望有一个明确说明的规格报价。

由于别名声明不能声明模板id,因此不可能部分地或显式地特化别名模板。

Bjarne说:

专门化工作(您可以对一组专门化进行别名,但不能对别名进行专门化)

并且,虽然不是一个明确的规则,"别名模板"在以下14.7.3/1的列表中缺失:

下列任意项的显式专门化:

  • 函数模板
  • 类模板
  • 类模板的成员函数
  • 类模板的静态数据成员
  • 类模板的成员类
  • 类或类模板的成员类模板
  • 类或类模板的成员函数模板

可以声明为[…]

我认为这是你能得到的最好的保证。

如果你需要从某物到类型的逐点映射,这是可行的(在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;
}

我不确定我是否理解这个问题,但无论如何,我都试图模拟别名模板的专门化。

我假设这个想法是将别名模板限制为特定的(模式匹配类型);我们过去对这类代码做的一些事情:

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

(这只是一个示例,还有其他方法可以从通用的std::vector中提取value_type)

现在是别名:

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

它做同样的工作,但这并不能取代old_stype<...>::type,因为它没有那么严格的限制。第一个尝试有一个完美的别名替换是这个假设的代码:

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

不幸的是,它不能编译(理论上是因为在其他答案和标准中陈述的名义原因,在实践中我想这是一个限制没有根本的原因)。幸运的是,我们可以退回到老式的struct::type方式,只使用新的别名模板特性来转发工作,

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;

可以使用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; 

可以用作:

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

如果需要任意数量的专门化(或代码中的非局部),则必须使用更复杂的define,分为两部分,一部分用于声明,另一部分用于专门化(应该是这样):

#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; 
};

用法如下:

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);
上面所有的代码都可以复制粘贴到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;
}

对不起,如果这不是你要找的。我相信它可以用于可变模板,以及额外的模板参数(在专门化中),但没有测试它。

欢迎改进