为什么我不能专门化std::tuple_element?

5
下面的程序试图为用户定义类型 foo 提供 std::tuple_element 的特化。不幸的是,在 libc++ 中,clang-3.5 拒绝了它,但在其他编译器或者使用其他标准库和 clang-3.5 一起使用时,程序被接受了。这是否正确?如果不是,请说明原因。
#include <utility>

struct foo {};

namespace std
{
    template<size_t, class> struct tuple_element;
    template<size_t i>
    struct tuple_element<i, foo> {};
}

int main()
{
    return 0;
}

编译器输出:
$ clang-3.5 -std=c++11 -stdlib=libc++ -lc++ test.cpp
test.cpp:11:8: error: explicit specialization of non-template struct 'tuple_element'
struct tuple_element<i, foo> {};
       ^            ~~~~~~~~
1 error generated.

$ clang-3.5 -std=c++11 -lstdc++ test.cpp
(no error)

$ g++-4.9 -std=c++11 test.cpp
(no error)
1个回答

8

libc++的实体实际上在std::__1::中,这是std内部的一个内联命名空间。因此,您自己的前向声明template<size_t, class> struct tuple_element;实际上声明了一个不同的类模板,然后由于歧义而导致部分特化失败(尽管错误消息是误导性的)。

删除前向声明即可解决问题。


1
struct 替换为 class 也可以修复一个警告。另外请注意,前向声明会使程序不合法,因为您可以在 std 中特化类型,但任何声明都是禁止的(即使是前向声明!)。构建中断是符合规范的。 - Yakk - Adam Nevraumont
2
@Yakk s/ill-formed/UB/,说起来有点迂腐。 - T.C.
1
那么,您是说原始帖子中的代码格式不正确吗?换句话说,提供标准库组件的声明是不合法的吗? - Jared Hoberock
3
你的代码向namespace std添加了一个声明。因此,行为是未定义的。 - Yakk - Adam Nevraumont

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