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.具有多种模板的容器库,如StackField和HeapField; 2.具有成员方法(如size)的实用程序库,其中字段作为模板参数(如您建议的第二种解决方法); 3.隐藏实现,并且在c ++中预先针对不同的字段进行了说明。4.用户使用诸如AField和的别名将应用程序A和B与此库链接BField。它可以与gcc一起使用,但在msvc中的链接失败,因为我的预先实例化的实现签名和用户调用不匹配
确实,别名模板不会引入新类型。但是您的类模板采用模板作为参数,而不是类型。和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)
| 归档时间: |
|
| 查看次数: |
81 次 |
| 最近记录: |