如何解决模板模板特化是否应该忽略模板别名,或者别名可以被视为不同的类型
我无法获得专为模板模板类与使用 clang 的一些别名一起工作的专业化。我制作了一个模板模板类 PointerHelper
(为了隐藏普通 STL 智能指针和我制作的自定义智能指针之间的使用差异)。我为模板类 PointerHelper
制作了 Pointer
的特化,但是在我想使用特化的地方,我为 Pointer
创建了一个模板别名,名为 MyPointer
。>
出于某种原因,当我使用显式模板参数引用 PointerHelper
时,clang 拒绝使用特化,而是选择默认实现。如果我添加一个包装模板函数来自动推导模板参数,一切都会按我的预期工作。如果我真的为我的别名添加了一个特化,clang 会很高兴,甚至使用别名的特化,而不是实际底层类型的特化。
经过几个小时的反复试验,我转到可信赖的编译器资源管理器来检查 MSVC 和 GCC 会说什么。 MSVC 同意 clang 我的代码已损坏,但 GCC 接受它作为有效代码。通常我倾向于假设,如果大多数编译器抱怨我的代码,我可能做错了什么,但在这种情况下我不太确定。
我想出了以下最小示例 (https://godbolt.org/z/r86Ynr18j):
#include <stdio.h>
template <typename T>
struct Pointer
{
operator bool() const
{
return true;
}
};
template <template <class> class PointerType,typename T>
struct PointerHelper
{
};
template <typename T>
struct PointerHelper<Pointer,T>
{
using TPointer = Pointer<T>;
static bool IsInitialized(const TPointer& ptr)
{
printf("Pointer\n");
return ptr;
}
};
template <template <class> class PointerType,typename T>
struct DoesSomethingWithPointers
{
using MyPointerHelper = PointerHelper<PointerType,T>;
using TPointer = typename MyPointerHelper::TPointer;
bool Initialized(TPointer ptr)
{
return MyPointerHelper::IsInitialized(ptr);
}
};
template <typename T>
using MyPointer = Pointer<T>;
// Clang and MSVC require this specialization,GCC thinks it's a redefinition
// template <typename T>
// struct PointerHelper<MyPointer,T>
// {
// using TPointer = Pointer<T>;
// static bool IsInitialized(const TPointer& ptr)
// {
// printf("MyPointer\n");
// return ptr;
// }
// };
// A wrapper template to auto-deduce the arguments always selects the correct specialization
template <template <class> class Ptr,typename T>
bool IsPointerInitialized(Ptr<T> ptr)
{
return PointerHelper<Ptr,T>::IsInitialized(ptr);
}
using Foo = int;
int main()
{
Pointer<int> p;
DoesSomethingWithPointers<Pointer,int> b;
if (b.Initialized(p))
printf("Initialized\n");
if (IsPointerInitialized(MyPointer<int>()))
printf("Initialized\n");
//fails on clang and MSVC if 2nd specialization isn't present:
DoesSomethingWithPointers<MyPointer,int> b2;
if (b2.Initialized(p))
printf("Initialized\n");
return 0;
}
如示例中的注释所述,当使用显式参数调用模板时,clang 和 MSVC 都要求我对别名进行特化(并且它们在执行代码时使用第二特化),即使根据我的理解别名不是一个不同的类型,而只是相同底层类型的不同标识符。使用包装模板函数自动推导模板参数可以解决问题。 GCC 的行为符合我的预期:它不需要别名特化,甚至抱怨我正在重新定义特化。
哪个编译器是正确的? (或者他们都是正确的,我只是做了一些没有指定的事情,但 GCC 足够友好,可以接受吗?)。
我尝试进行网络搜索以查看这是否是一个已知问题,但我找不到任何内容(这很可能是由于我没有使用正确的术语造成的)。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。