为什么MSVC无法编译这个模板函数?
Why does MSVC fail to compile this template function?
我在将一些代码移植到MSVC时遇到了一个问题,这让我很困惑。据我所知,代码应该是合法的,Clang可以很好地编译它。
我把范围缩小到以下几个:
enum E {
x
};
template <typename T>
struct traits {
static const E val = x;
};
template <E e>
struct S {
S(){};
};
template <typename T>
S<traits<T>::val> foo(T t);
int main() {
char c = 0;
foo(c);
}
请注意,在编译之后,代码预计会产生一个链接器错误(我剥离了函数foo
的定义以保持示例最小化),但是据我所知,它应该可以清晰地编译。然而,MSVC给了我这个错误:
错误C2893:特化函数模板'S::val> foo(T)'失败
我的问题是:
- MSVC拒绝代码是否正确?(如果是,为什么?)
- 如果没有,谁能缩小它做错了什么?也就是说,这是一个他们根本没有实现的语言特性(比如模板的两阶段名称查找),还是"仅仅"是他们声称支持的特性实现中的一个明显错误?
我已经在vc++ 2010和2012上重现了这个问题。
在我自己运行了一些测试之后,这似乎是MSVC中的编译器错误。虽然它在GCC中工作得很好,但当您试图在模板参数中使用traits<T>::val
以返回S< E e >
时,MSVC会给出神秘且无益的编译器错误(与您问题中的错误相同)。
有趣的是,当您将S< E e >
更改为整数时,它可以工作。考虑以下示例,与您的示例相同,只是命名不同:
enum E {
x
};
template <typename T>
struct traits {
static const E val = x;
};
template <E e>
struct S {
S(){};
};
template <typename T>
S< traits<T>::val > tricky(T t) {
return S< traits<T>::val > ();
};
int main() {
char thiskidwhowalksaround = 0;
S<x> s = tricky( thiskidwhowalksaround );
}
现在,让我们只改变一件事:
template <int e> // int instead of E
struct S {
S(){};
};
程序为我完美地编译(链接和运行)。如果您也恢复到原始状态,然后直接传递E
的值,如:
template <typename T>
S< x > tricky(T t) {
// ^ here
return S< x > (); // <-- here
};
然后程序编译文件。MSVC在尝试做以下事情时遇到了失败的问题:
traits<T>::val
,其中val
是任意类型的枚举。我99%肯定这是编译器本身的缺陷。这似乎是一个结构完美的c++,所以我不能说GCC做错了什么,也不能说原始代码片段正常工作是在扩展。因此,我能收集到的最好的信息是,与同类产品相比,MSVC在编译器健壮性方面有所欠缺。
你可以在这里停止阅读,因为现在我要花一点时间来抱怨MSVC编译器。
begin<rant>
这并不是说vc++团队不好或者c++不好,但是从我收集到的微软编译器团队和标准库团队的信息来看——截止到写这篇文章的时候——与其他部门相比,非常小。令我恼火的是,如此基础和重要的语言,以及微软行业核心的一部分,却只有相对较少的人力,以至于它无法跟上——在我短暂的一生中——我发现它是世界上发展最慢的标准之一。我当然不是在批评那些在vc++团队工作的人,但我深感困惑的是,为什么没有更多的人致力于提高c++的速度,而且使编译器工作得更好,和其他产品领域一样好。end<rant>
- C++17中函数模板中的静态数组初始化(MSVC 2019)
- std::vector::p ush_back() 不会在 MSVC 上编译具有已删除移动构造函数的对象
- MSVC 和函数参数的 constexpr?
- constexpr 函数的常量引用参数:gcc/msvc vs clang/icc
- MSVC 2017 - 错误 - 如何将模板类 X 的模板成员函数声明为嵌套类 X::Y 的好友
- 将内联程序集尾调用函数尾声替换为用于x86/x64 msvc的Intrinsics
- 为什么 MSVC 在使用正确的签名覆盖函数时会产生 C3668 错误?
- std::value templated 方法的函数使用 clang 和 g++ 进行编译,但不使用 msvc 进行编译
- 继承基构造函数,基类是模板参数 (MSVC)
- constexpr 函数中的 for 循环无法使用 MSVC 19.23 进行编译
- MSVC 编译器/链接器何时合成标量/矢量删除析构函数
- x64 函数调用参数推送/移动顺序 (MSVC)
- C++具有可变参数包的函数的部分模板参数推导会在 Clang 和 MSVC 中产生不明确的调用
- enable_if is_same constexpr函数使MSVC失败(但在Clang,GCC中效果很好)
- MSVC:带函数的"error C2244: unable to match function definition to an existing declaration"是指专用模板类的类型别名
- MSVC 无法识别继承模板类的模板类的"直接"基类构造函数
- MSVC 2017 在共享库中创建模板函数的副本
- MSVC 在不应该调用时内联虚拟函数调用
- 已删除的构造函数 - MSVC 报告错误,Clang 不报告
- 在__device__函数(MSVC)中找不到CUDA copyign()函数