提问人:user541686 提问时间:9/11/2023 最后编辑:Jan Schultkeuser541686 更新时间:9/12/2023 访问量:100
为什么我不能在 MSVC 中专用化具有返回类型别名模板的模板?
Why can't I specialize a template with an alias template in the return type in MSVC?
问:
MSVC 拒绝编译此内容:
#include <type_traits>
struct G { void operator()() const { } };
template<class T>
using MyTrait = std::is_void<T>;
struct S
{
template<class F>
std::enable_if_t<MyTrait<decltype(std::declval<F>()())>::value> run(F &&);
};
template<>
void S::run(G &&);
出现以下错误:
<source>(14): error C2910: 'S::run': cannot be explicitly specialized
<source>(16): error C2760: syntax error: 'int' was unexpected here; expected ';'
但是 Clang 和 GCC 编译得很好。如果我说而不是.std::is_void
MyTrait
为什么会这样?是编译器错误,还是语言中的某些东西导致了这个问题?
答:
2赞
Jan Schultke
9/11/2023
#1
这是一个编译器错误。定义成员函数模板的显式专用化是完全合法的。
std::enable_if_t<MyTrait<decltype(std::declval<F>()())>::value>
最终是 SFINAE 的别名,使用别名不应阻止专业化。void
在声明器 ID 引用函数模板专用化的声明中,将执行模板参数推导以标识声明所引用的专用化。 具体来说,这是针对显式实例化、显式专用化和某些友元声明完成的。
确定完全专用化是否与成员函数模板匹配的过程与调用 where is 类型的参数的过程相同。void S::run(G&&)
S::run(g)
g
G
在此过程中,哪里会变成 .std::enable_if_t<MyTrait<decltype(std::declval<F>()())>::value>
F = G
void
值得注意的是,您的示例确实编译了:
template<class F>
std::enable_if_t<MyTrait<decltype(G{}())>::value> run(F&&);
...这几乎是一回事,MSVC 在这里不一致。
有关 MSVC 版本的说明
MSVC 19.35 对此进行了编译,但较新的版本引发了错误。我无法找到此问题的错误报告,可能是因为它相对较新,还没有人注意到/报告它。
错误报告
我已经为此问题提交了错误报告。
评论
0赞
303
9/28/2023
非常感谢您向 Microsoft 提交错误报告!我认为还值得注意的是,这个问题的另一种解决方法是从类型特征派生而不是别名,如:template<typename T> struct MyTrait : std::is_void<T> {};
评论
run
/std:c++17