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

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

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

type_alias上的C ++参考说

  

它没有引入新的类型

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

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

template<typename T>
struct CurrentField
{
 alias type = Field<T> ;
};

编辑:

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

共有4个部分:  1.一个具有多种模板(例如StackFieldHeapField)的容器库,  2.一个实用程序库,具有成员方法(如size),字段作为模板参数(如您建议的第二种解决方法),  3.在C ++中,针对不同的领域,实现已被隐藏和预先实例化。  4.用户使用AFieldBField之类的别名将应用程序A和B与此库链接。它可以与gcc一起使用,但是在msvc中的链接失败,因为我预先实例化的实现签名和用户调用不匹配

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

确实,别名模板不会引入新类型。但是您的类模板采用模板作为参数,而不是类型。 FieldCurrentField都是模板。因此,这归结为以下问题:CurrentField应该算作与Field相同的模板还是算作单独的模板。这是CWG issue 1286。另请参见this thread。 GCC遵循第一种解释,clang和MSVC遵循第二种解释……

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

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

    template <typename T> 
    using CurrentField = typename CurrentFieldHelper<T>::type;

工作示例here

恐怕没有办法实现相反的目标,即,使所有编译器都将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);
}
本文链接:https://www.f2er.com/3015193.html

大家都在问