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中链接失败,因为我的预实例化实现的签名和用户调用不匹配

最佳答案

别名模板确实不会引入新类型。但是您的类模板采用模板作为参数,而不是类型。 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);
}

09-10 05:25
查看更多