为什么MSVC编译这个模板函数失败?

12

我在将一些代码移植到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 是否有可能正确地拒绝该代码?(如果是,为什么?) - 如果不是,是否可以缩小其出错的范围?也就是说,它是一个语言功能,他们根本没有实现(如用于模板的两阶段名称查找),还是在其声称支持的功能实现中存在“普通”的 bug?
我已经在 VC++2010和2012上重现了此问题。

这与之前的问题有关吗?在类型推导后,函数模板中替换顺序是否有保障? - Bo Persson
@BoPersson:在我看来似乎与此无关。我想不出其他原因,除了这里有一个错误。顺便说一下,在GCC 4.7.2上它的工作正常。 - Andy Prowl
此外,如果您将“enum”替换为“int”,错误就会消失。这似乎是与“enum”相关的错误。 - Andy Prowl
当然有一个错误。编译器未能执行这样或那样的操作,谁在乎呢?我需要知道我的程序违反了哪个语言规则,并引用标准中更为晦涩的内容。一些编译器作者就是没有头绪。尽管如此,我会尝试实例化traits <char>S <traits <char> ::val>,只是为了看看编译器的反应。 - n. m.
@n.m.:没有人说“这是一个错误”就足够了。我们只是写评论。此外,由于我认为这是编译器的错误,我相信程序没有违反任何规则。 - Andy Prowl
1个回答

3
在我自己进行了一些测试后,这似乎是MSVC编译器的一个错误。虽然使用GCC很好,但当您尝试在S< E e >返回类型的模板参数中使用traits<T>::val时,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>


这确实是一个编译器错误。我在Connect上报告了它,他们只是表示它将在“下一个Visual C++版本”中修复...无论那是什么时候。 - jalf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接