简体   繁体   中英

C++20 NTTP specialization

There is disagreement between gcc/clang and msvc when trying to compile the following code:

struct foo {
};

// primary template
template<auto>
struct nttp {
    static constexpr int specializaion = 0;
};

// specialization
template<foo f>
struct nttp<f> {
    static constexpr int specializaion = 1;
};

int main() {
  // Does not compile with msvc 19.30
  nttp<5> x{};
}

Full example here .

Msvc is complaining that there is no viable conversion from int to foo which is obviously true, but shouldn't be of any relevance here as far as I understand the rules of partial template specialization.

Quoting cppreference :

When a class or variable (since C++14) template is instantiated, and there are partial specializations available, the compiler has to decide if the primary template is going to be used or one of its partial specializations.

  1. If only one specialization matches the template arguments, that specialization is used
  2. If more than one specialization matches, partial order rules are used to determine which specialization is more specialized. The most specialized specialization is used, if it is unique (if it is not unique, the program cannot be compiled)
  3. If no specializations match, the primary template is used

I'd argue that there is no matching spezialization for int in this case hence the primary template should be selected.

Interestingly, the situation can be fixed by constraining the auto in the specialization by a concept:

template<class T>
concept Foo = std::is_same_v<T, foo>;

template<auto>
struct nttp {
    static constexpr int specializaion = 0;
};

template<Foo auto f>
struct nttp<f> {
    static constexpr int specializaion = 2;
};

// compiles with all compilers
static_assert(nttp<5>{}.specializaion == 0);

Function templates work as expected, too:

constexpr int test(auto) {
    return 0;
}

constexpr int test(foo) {
    return 1;
}

// compiles with all compilers
static_assert(test(5) == 0);

Long story short: empirically and intuitively I'd say that this is a bug in MSVC, but as always there's a chance that UB is involved here. So the question would be: are clang/gcc correct, or MSVC, or even all of them?

This is open MSVC bug report:

Your program is well-formed as per [temp.class.spec.match]/2 and [temp.class.spec.match]/3 :

/2 A partial specialization matches a given actual template argument list if the template arguments of the partial specialization can be deduced from the actual template argument list, and the deduced template arguments satisfy the associated constraints of the partial specialization, if any.

/3 If the template arguments of a partial specialization cannot be deduced because of the structure of its template-parameter-list and the template-id, the program is ill-formed.

/3 was specifically updated as part of P0127R2 ( Declaring non-type template parameters with auto ), which re-wrote the previously revised wording from the resolution of CWG1315

(After CWG1315, before P0123R2) /3 Each template-parameter shall appear at least once in the template-id outside a non-deduced context.

This re-write was done particularly to allow partial specialization over non-template parameters declared with the auto placeholder type.

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