什么时候两个不同的类模板偏特化声明匹配?
在下面的代码中有两个偏特化声明:
-
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 ,“等效但功能不等效的重新声明”:
In an example like
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();
it appears that the second declaration of
f
is a redeclaration of the first but distinguishable by SFINAE, i.e., equivalent but not functionally equivalent.Notes from the November, 2014 meeting:
CWG felt that these two declarations should not be equivalent.
这仍然是一个活跃的问题。 gcc 的行为更符合这些不同的愿望。 [temp.alias]/2和 [temp.alias]/3是相关的透明度规则:
When a template-id refers to the specialization of an alias template, it is equivalent to the associated type obtained by substitution of its template-arguments for the template-parameters in the type-id of the alias template.
However, if the template-id is dependent, subsequent template argument substitution still applies to the template-id.
这里有冲突。在问题的简化示例中,X<T, U>
相当于 T
- 这意味着两个声明的返回类型都是 void
- 但替换仍然适用,这并不完全意味着它们是等价的。
关于c++ - 类模板偏特化等价,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52255175/