类模板部分专用化等效性

Class template partial specialization equivalence

本文关键字:专用 板部      更新时间:2023-10-16

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

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

  • 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,"等效但不是功能等效的重声明":

在类似的例子中

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认为,这两个声明不应等同。

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

当模板 id 引用别名模板的

专用化时,它等效于通过将其模板参数替换为别名模板的类型id中的模板参数而获得的关联类型。

但是,如果模板ID 是依赖的,则后续模板参数替换仍适用于模板 ID

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