【问题标题】:Alias template specialisation别名模板专业化
【发布时间】:2011-07-08 09:25:32
【问题描述】:

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

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

文本“当一个模板ID 指代一个别名模板的特化”暗示是,但随后的例子似乎指的是别的东西,暗示否 .

注意。我在 n3242 工作,它位于 FDIS 后面,本节的标题是“别名模板”。哈哈。

【问题讨论】:

  • 对于一般公共信息,我想提一下clang支持别名模板。
  • @Johannes:请提供版本信息 :)
  • @Johannes: 是的,我read that before 一次;)
  • 由于这个问题有点老,这可能无关紧要,但别名声明在 gcc 4.7.3 中有效。
  • @cheshirekow:感谢您的更新。 ;)

标签: c++ templates c++11


【解决方案1】:

标准中“专业化”的意思是将通用模板转换为更专业的实体。例如,实例化一个非成员类模板会产生一个不再是模板的类。术语“专业化”是双重的,可以指生成的专业化(这是一种被实例化的专业化,可能来自部分专业化)和显式专业化(这是您所指的)。

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

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&lt;T&gt; 时完成的(这样的名称用于指代类或函数模板特化;因此规范将此类名称描述为“指代别名模板的特化”)。即f的参数类型为T&amp;,因此可以推导出T。此属性防止别名模板的显式或部分特化。因为为了选择ref 的正确专业化,它需要知道T。但是要知道它,它需要将ref&lt;T&gt; 与参数类型进行比较以推断出T。总结在论文N1406, "Proposed addition to C++: Typedef Templates",第2.2节

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

在对反射器和 Evolution WG 进行讨论之后,事实证明我们必须在两个互斥模型之间进行选择:

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

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

    • typedef模板函数参数推导(见2.4)
    • 使用 typedef 模板表达的声明与不使用 typedef 模板的声明相同 typedef 模板(见 2.5)
    • typedef 模板匹配模板模板参数(见 2.6)

需要注意的是,支持选项 1 的引用论文并未进入 C++0x。


编辑:因为您迫切希望有一个明确的规范引用。 14.5p3 是这样的

因为别名声明不能声明模板 ID,所以不能部分或显式特化别名模板。

【讨论】:

  • 哇,这扼杀了我对模板别名的大部分预期用途。我期待着摆脱除了保存 typedef 之外没有其他用途的结构。
  • @JosephGarvin,这对吗?是否必须退回到旧的 struct 定义模板 typedef 的方式?
  • @alfc:仅当您想专门化 typedef 时。后来我意识到这还不错——你可以有一个专门的模板的模板别名。只有别名本身不能被特化,这在实践中并不常见。
【解决方案2】:

比亚恩says:

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

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

以下任何一项的明确特化:

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

可以声明[...]

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

【讨论】:

  • 想发布一些很好的例子吗?我想复制/粘贴并测试一些编译器。我相信 GCC 4.4 根本没有支持,我现在也不知道 4.6.1...
  • @Kerrek:我从来没有时间制作任何东西。 :)
  • template &lt;typename T, int N&gt; struct A { static const int value = N; }; template &lt;typename T&gt; using V = A&lt;T, 42&gt;; template &lt;&gt; using V&lt;int&gt; = A&lt;42, 48&gt;; int main() { std::cout &lt;&lt; V&lt;char&gt;::value &lt;&lt; ", " &lt;&lt; V&lt;int&gt;::value; },我猜。
  • 遗憾的是,即使在 GCC 4.6.1 中也不支持模板别名 :-(
  • @Tomalak Geret'kal:您的代码和 clang 主干:“错误:不允许明确专门化别名模板”
【解决方案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;
}

【讨论】:

    【解决方案4】:

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

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

    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&lt;...&gt;::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);
    

    以上所有代码都可以复制粘贴进行测试:

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

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

    非常欢迎改进。

    【讨论】:

    • 哈,+1 因为这很好。不过,它最终只是一个用于专门化 structs 的预处理器包装器。
    • @LightnessRacesinOrbit,是的,但别名末尾没有::type。
    猜你喜欢
    • 1970-01-01
    • 2013-12-04
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多