Why can't I specialize std::tuple_element?
Asked Answered
M

1

5

The following program attempts to provide a specialization for std::tuple_element for the user-defined type foo. Unfortunately, clang-3.5 rejects it with libc++, but using other compilers or using other standard libraries with clang-3.5 accept the program. Is it correct? If no, why not?

#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;
}

Compiler output:

$ 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)
Maury answered 23/7, 2015 at 20:42 Comment(0)
D
8

libc++'s entities are actually in std::__1::, an inline namespace inside std. So your own forward declaration template<size_t, class> struct tuple_element; actually declares a different class template, and then the partial specialization blows up due to ambiguity (though the error message is misleading).

Remove the forward declaration and it should work.

Deena answered 23/7, 2015 at 20:47 Comment(4)
Replacing struct with class fixes a warning as well. Also note that the forward declaration makes the program ill-formed, as you are free to specialize types in std, but any declaration is verboten (even a forward declaration!). The build break is compliant.Cupreous
@Yakk s/ill-formed/UB/, to be pedantic.Deena
So, are you saying the code from the original post is ill-formed? In other words, it's not legal to provide declarations of standard library components?Maury
17.6.4.2.1 Namespace std [namespace.std]/1 -- your code adds a declaration to namespace std. Behavior is thus undefined.Cupreous

© 2022 - 2024 — McMap. All rights reserved.