首页 文章

类模板部分特化等价

提问于
浏览
11

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

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

  • 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 回答

  • 10

    这是CWG 1980,"Equivalent but not functionally-equivalent redeclarations":

    在类似模板<typename T,typename U>的例子中使用X = T;
    template <typename T> X <void,typename T :: type> f();
    template <typename T> X <void,typename T :: other> f();
    似乎f的第二个声明是对第一个声明的重新声明,但是SFINAE可以区分,即等效但不是功能等同 . 2014年11月 Session 的说明:CWG认为这两个声明不应该是等同的 .

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

    当template-id引用别名模板的特化时,它等效于通过替换别名模板的type-id中的template-parameters的template-arguments获得的关联类型 . 但是,如果template-id是依赖的,则后续模板参数替换仍适用于template-id .

    这里有冲突 . 在该问题的简化示例中, X<T, U> 等同于 T - 这意味着两个声明只有 void 的返回类型 - 但替换仍然适用,而且它不等同于't exactly mean they' .

相关问题