代码之家  ›  专栏  ›  技术社区  ›  Oliv

类模板部分专用化等价

  •  11
  • Oliv  · 技术社区  · 6 年前

    两个不同的类模板部分专用化声明何时匹配?

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

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

    关于部分专门化声明等价,标准怎么说?

    1 回复  |  直到 6 年前
        1
  •  10
  •   Arne Vogel    6 年前

    这是 CWG 1980 “等价但非功能等价的再声明”:

    例如

    template<typename T, typename U> using X = T;
    template<typename T> X<void, typename T::type> f();
    template<typename T> X<void, typename T::other> f();
    

    第二次声明 f 是对第一个的重新定义,但可由sfinae区分,即等效但功能上不等效。

    2014年11月会议纪要:

    CWG认为这两个声明不应该是等效的。

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

    当A 模板ID 是指别名模板的专门化,它相当于通过替换其 模板参数 对于 模板参数 类型ID 别名模板的。

    但是,如果 模板ID 依赖,后续模板参数替换仍应用于 模板ID .

    这里有冲突。在问题的简化示例中, X<T, U> 相等的 T -这意味着两个声明的返回类型都是 void -但替代仍然适用,这并不意味着他们 相等的 .