简体   繁体   中英

Implicit type conversion between size_t and int using templates

I have this compile-time sequence generation class (taken from here , and modified it a little bit):

#include <cstddef>

template <int...>
struct sequence {};

template <int... Ns>
struct generator;

template <std::size_t Count, int... Ns>  // XXX (read below)
struct generator<Count, Ns...> {
    using type = typename generator<Count - 1, Count - 1, Ns...>::type;
};

template <int... Ns>
struct generator<0, Ns...> {
    using type = sequence<Ns...>;
};

template <std::size_t N>
using sequence_t = typename generator<N>::type;

int main() {
    sequence_t<5> a;
    return 0;
}

This compiles fine under Visual Studio (even with the /permissive- switch). But it throws errors under GCC:

g++: error: template argument '(int)Count' involves template parameter(s)
g++:  struct generator<Count, Ns...> {
...

It throws errors under Clang as well:

clang++: error: ambiguous partial specializations of 'generator<0, 0, 1, 2, 3, 4>'
clang++:    using type = typename generator<Count - 1, Count - 1, Ns...>::type;
...
clang++: note: partial specialization matches [with Count = 0, Ns = <0, 1, 2, 3, 4>]
clang++: struct generator<Count, Ns...> {
clang++:
clang++: note: partial specialization matches [with Ns = <0, 1, 2, 3, 4>]
clang++: struct generator<0, Ns...> {

After changing the size_t type in marked line (marked as XXX (read below) ) to int , everyone compiles this sample code properly.

Who is right in this case? Visual Studio because it compiles the code, or GCC+Clang because it doesn't allow it to be compiled?

Why Visual Studio is able to compile the sample just fine? Does it have more relaxed implicit conversion rules than other compilers? Or is there a different reason for it? Any link that would point me to a document that could help me to decode these error messages would also be appreciated:)

This is due to active language defect CWG issue 1647 :

The Standard appears to be silent on whether the types of non-type template arguments in a partial specialization must be the same as those of the primary template or whether conversions are permitted

There is implementation variance in the treatment of this...

So there is no right compiler here since no clear requirements exist in the standard how to treat such specializations.

Please note that GCC and Clang diverge and fail this example due to different reasons. Demo: https://gcc.godbolt.org/z/41cbPePPW

Clang cannot prefer one of two specializations:

error: ambiguous partial specializations of 'generator<0, 0, 1, 2, 3, 4>'

And GCC completely ignores the specialization struct generator<Count, Ns...> trying to instantiate the main template and failing due to lack of its definition:

error: invalid use of incomplete type 'struct generator<5>'

In GCC the corresponding bug is reported in 2014 ( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60679 ) and currently is on hold waiting for C++ standard clarification.

As the question says, the replacement of size_t with int is the best here, resolving all the problems, demo: https://gcc.godbolt.org/z/fY9hxsT7P

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM