什么时候两个不同的类模板局部特化声明匹配?

在下面的代码中,有两个部分特化声明:

  • 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]在这里似乎并不适用。

    该标准对部分专业声明的等效性说了什么?

    最佳答案

    这是CWG 1980,“等效但不等效的重新声明”:



    这仍然是一个活跃的问题。 gcc的行为更符合这些不同的愿望。 [temp.alias]/2[temp.alias]/3是相关的透明度规则:



    在这里有冲突。在此问题的简化示例中,X<T, U>等效于T-这意味着两个声明都具有void的返回类型-但是替换仍然适用,并不完全意味着它们等效。

    关于c++ - 类模板部分特化的对等,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52255175/

    10-11 22:50
    查看更多