类模板别名不应在生成的符号中可见,对吗?

pie*_*tee 7 c++ alias templates language-lawyer c++11

当编译该snipet在godbolt,大多数编译器产生两个不同的get方法(在装配窗口不同的符号):

template<typename  T> 
struct Field { T impl; };

template<typename  T> 
using CurrentField = Field<T>;

template<template <typename> class F> 
struct Encompassing { F<int> member; };


auto get(Encompassing<Field> const& instance)
{
    return instance.member.impl;
}
auto get(Encompassing<CurrentField> const& instance)
{
    return instance.member.impl;
}
Run Code Online (Sandbox Code Playgroud)

CurrentField即使是别名,我也看到了符号。只有gcc抱怨重新定义(如预期)。

关于type_alias的 C ++参考说

它没有引入新的类型

所以我认为它不应该这样表现,我错了吗?

实际上,大多数编译器的行为似乎是将别名模板替换为类Trait

template<typename T>
struct CurrentField
{
 alias type = Field<T> ;
};
Run Code Online (Sandbox Code Playgroud)

编辑:

这是我尝试在Godbolt上实现的目标的更具代表性的示例。请注意,由于只有一个源并且没有链接,所以它可以编译,但msvc程序集显示它既生成了预先实例化的签名又生成了用户调用签名。

它分为4个部分:1.具有多种模板的容器库,如StackFieldHeapField; 2.具有成员方法(如size)的实用程序库,其中字段作为模板参数(如您建议的第二种解决方法); 3.隐藏实现,并且在c ++中预先针对不同的字段进行了说明。4.用户使用诸​​如AField和的别名将应用程序A和B与此库链接BField。它可以与gcc一起使用,但在msvc中的链接失败,因为我的预先实例化的实现签名和用户调用不匹配

Mic*_*zel 2

确实,别名模板不会引入新类型。但是您的类模板采用模板作为参数,而不是类型。和Field都是CurrentField模板。因此,这归结为一个问题:是否CurrentField应将其视为同一模板,Field还是应将其视为单独的模板。这是CWG 第 1286 期。另请参阅此线程。GCC 遵循第一种解释,clang 和 MSVC 遵循第二种……

一种解决方法似乎是通过帮助程序模板来打破CurrentFieldto的直接映射:Field

    template <typename T>
    struct CurrentFieldHelper { using type = Field<T>; };

    template <typename T> 
    using CurrentField = typename CurrentFieldHelper<T>::type;
Run Code Online (Sandbox Code Playgroud)

工作示例在这里

恐怕没有办法实现相反的效果,即让所有编译器都将 视为get(Encompassing<CurrentField> const &)相同的函数get(Encompassing<Field> const &)。如果不了解更多关于实际代码的信息,就很难针对这个特定问题提出解决方法。一个简单的解决方案可能适用于您的实际代码,也可能不适用于您的实际代码,那就是创建size一个函数模板,将其解包instance.member然后将其转发到执行实际工作的通用函数:

template <template <typename> class F> 
auto size(Encompassing<F> const& instance)
{
    return size(instance.member);
}
Run Code Online (Sandbox Code Playgroud)