Когда совпадают объявления двух отдельных классов шаблонов?
В приведенном ниже коде есть две частичные объявления специализации:
-
S<constrain<T,has_accept_>, void>
-
S<constrain<T,has_visit_>, void>
constrain
- это шаблон псевдонима, равный T
но ограниченный с помощью enable_if
со вторым параметром в качестве концепции.
GCC считает, что эти две частичные специализации различны, но Clang и MSVC считают, что они эквивалентны и, таким образом, отвергают код:
#include <type_traits>
#include <utility>
using namespace std;
template<class T,class=void>
struct has_accept
:false_type{};
template<class T>
struct has_accept<T,void_t<decltype(declval<const T&>().accept())>>
:true_type{};
template<class T,class=void>
struct has_visit
:false_type{};
template<class T>
struct has_visit<T,void_t<decltype(declval<const T&>().visit())>>
:true_type{};
//pre c++17 clang/MSVC fix: default argument of template
// used as template template argument not implemented yet
template<class T> using has_accept_ = has_accept<T>;
template<class T> using has_visit_ = has_visit<T>;
template<class T,template<class> class TT,class=enable_if_t<TT<T>::value>>
using constrain = T;
template<class T,class=void>
struct S
:false_type{};
template<class T>
struct S<constrain<T,has_accept_>,void> // (1)
:true_type{};
template<class T>
struct S<constrain<T,has_visit_>,void> // (2)
:true_type{}; // ==> MSVC and Clang: error (2) redefines (1)
Я не могу найти ничего в стандарте, который бы указывал на эквивалентность частичной специализации. [temp.type], похоже, не применяется здесь.
Что говорит стандарт об эквивалентности декларации частичной специализации?