别名模板专门化
Alias template specialisation
别名模板(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的讨论,我们不得不在两个相互排斥的模型之间做出选择:
typepedef模板本身不是别名;只有typedef模板的实例化(可能是专门化的)才是别名。
一个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;
}
对不起,如果这不是你要找的。我相信它可以用于可变模板,以及额外的模板参数(在专门化中),但没有测试它。
欢迎改进
- 部分定义/别名模板模板参数
- 如何在C++20中创建模板别名的推导指南
- 是否可以对零模板参数进行模板专门化
- 告诉c++编译器该参数没有别名
- boost::spirit::karma 替代生成器,带有 boost::variant 由字符串和字符串别名组成
- 继承模板类中的类型别名
- 尝试根据类中 typedef 的存在来专门化模板函数
- 别名模板的专业化 C++11 中没有开销的最佳替代方案
- 为什么 GCC 在使用类型别名时处理 const reinterpret_cast不同?
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 如何基于模板化类的基类专门化成员函数
- 为什么我们不能重复使用具有不同模板参数的别名模板标识符?
- C++模板/别名 - 模板参数列表中参数 1 处的类型/值不匹配
- 如何使用类型别名从模板化类中隐藏模板列表
- C++11`using`关键字:专门化模板参数的模板别名
- 模板化别名声明的部分专门化
- 如何根据模板参数是否具有别名来专门化类型
- 我可以用别名模板专门化一个类模板吗?
- 模板别名、模板专门化和模板参数
- 别名模板专门化