为什么MSVC无法编译此模板函数?

时间:2013-03-17 21:44:40

标签: c++ templates visual-c++

我遇到了将一些代码移植到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)'

所以我的问题:

  • MSVC是否有机会正确拒绝代码? (如果是,为什么?)
  • 如果没有,任何人都可以缩小它的错误吗?就像在,它是一个根本没有实现的语言功能(例如模板的两阶段名称查找),还是“只是”他们声称支持的功能实现中的一个普通错误?

我在VC ++ 2010和2012上重现了这个问题。

1 个答案:

答案 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>