我遇到了将一些代码移植到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&gt; FOO(T)'
所以我的问题:
我在VC ++ 2010和2012上重现了这个问题。
答案 0 :(得分:3)
自己运行一些测试后,这似乎是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做错了什么或扩展-y让原始代码片段工作。因此,我能收集到的最好的结果是,MSVC与同行相比缺乏编译器的稳健性。
你可以在这里停止阅读,因为现在我将花一点时间来讨论MSVC编译器。
begin<rant>
并不是说VC ++团队不好或C ++不好,而是从我收集编译器团队和Microsoft的标准库团队 - 到撰写本文时 - 是 tiny 与其他部门相比。令我感到困惑的是,这种基本而重要的语言和MS行业的核心部分具有相对较少的人力,无法跟上什么 - 在我短暂的一生中 - 我发现它是世界上最慢的移动标准之一。我当然不是那些在VC ++团队工作的人,但我为什么没有更多的人致力于使C ++不仅速度提高,而且让编译器更好地工作以及和其他人一样好,我感到非常困惑。产品领域。
end<rant>