别名模板专业化

时间:2011-07-08 09:25:32

标签: c++ templates c++11

别名模板(14.5.7)可以明确专门化(14.7.3)吗?

我的标准功能使我失望,我找不到要测试的编译器。

文本“当模板ID引用别名模板的特化时”暗示,但是示例似乎引用了其他内容,暗示

NB。我在n3242工作,一个在FDIS后面,其中本节的标题是“别名模板”。洛尔。

4 个答案:

答案 0 :(得分:26)

“专业化”标准的含义是将通用模板转换为更专业的实体。例如,实例化非成员类模板会产生一个不再是模板的类。术语“专业化”是两个部分,可以指生成的特化(这是一个实例化的特化,可能来自部分特化)和一个显式特化(这是你所提到的)。

别名模板未实例化,并且没有专门化的模板。他们无法实例化。相反,每当它们的名称后跟一个模板参数列表时,表示的类型是通过用别名类型替换名称和参数列表获得的类型,用参数列表中给出的参数替换所有模板参数引用。也就是说,别名模板本身不是别名的专用,而是作为别名,而不需要实例化任何东西。这种替换很早就完成了。考虑:

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, "Proposed addition to C++: Typedef Templates",第2.2节

中进行了总结
  

2.2主要选择:专业化与其他一切

     

经过对反射器和Evolution WG的讨论后,我们发现我们必须在两种相互排斥的模型之间进行选择:

     
      
  1. typedef模板本身不是别名;只有typedef模板的(可能是专用的)实例化才是别名。这个选择允许我们对typedef模板进行专门化。

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

         
        
    • 对typedef模板函数参数的推论(见2.4)
    •   
    • 使用typedef模板表示的声明与不声明声明相同   typedef templates(见2.5)
    •   
    • typedef模板以匹配模板模板参数(参见2.6)
    •   
  4.   

应该注意的是,所引用的论文(有利于选项1)没有使其成为C ++ 0x。


编辑:因为你非常想要一个明确说明的规范引用。 14.5p3就是

  

由于别名声明无法声明模板ID,因此无法部分或明确地专门化别名模板。

答案 1 :(得分:7)

Bjarne says

  

专业化工作(您可以为一组专业化设置别名,但不能专门化别名)

而且,虽然不是一个明确的规则,但是在14.7.3 / 1的以下列表中缺少“别名模板”:

  

以下任何一项的明确专业化:

     
      
  • 功能模板
  •   
  • 课程模板
  •   
  • 类模板的成员函数
  •   
  • 类模板的静态数据成员
  •   
  • 类模板的成员类
  •   
  • 类或类模板的成员类模板
  •   
  • 类或类模板的成员函数模板
  •   
     

可以声明[...]

我认为这是您获得的最佳保证。

答案 2 :(得分:4)

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

我认为这个想法是将别名模板限制为某些(模式匹配类型);我们以前用这种代码做的事情:

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

(这只是一个示例,还有其他方法可以提取通用value_type的{​​{1}}。

现在到了别名:

std::vector

它执行相同的工作,但这不会取代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);

很抱歉,如果这不是您想要的。我相信它可以与变量模板一起使用,并使用额外的模板参数(在专业化中),但没有测试它。

非常欢迎改进。

答案 3 :(得分:3)

如果你需要从某些东西到类型的逐点映射,这适用于(在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;
}