SFINAE方法完全禁用clang中基类的模板方法 [英] SFINAE method completely disables base class's template method in clang
问题描述
#include <iostream>
#include <utility>
struct B {
template<typename T, std::enable_if_t<std::is_same<T, int>::value>* = nullptr>
void foo(T) {
std::cout<<"B::foo"<<std::endl;
}
};
struct D: B {
using B::foo;
template<typename T, std::enable_if_t<std::is_same<T, std::string>::value>* = nullptr>
void foo(T) {
std::cout<<"D::foo"<<std::endl;
}
};
int main() {
D d;
d.foo(2); // gcc: print "B::foo"; clang: compile error
return 0;
}
假设我们要在派生类D中公开这两个foo()
重载.gcc和Visual Studio编译并按我的预期打印"B :: foo".但是我收到了clang的编译错误:
Let's say we want to expose both foo()
overloads in derived class D. gcc and Visual Studio compiles and print "B::foo" as I expected. But I get a compile error with clang:
prog.cc:22:7: error: no matching member function for call to 'foo'
d.foo(2);
~~^~~
prog.cc:14:10: note: candidate template ignored: requirement 'std::is_same<int, std::string>::value' was not satisfied [with T = int]
void foo(T) {
这是一个叮叮当当的错误吗?谢谢!
Is this a clang bug? Thanks!
推荐答案
我实际上认为这是gcc错误( 84832 密切相关,尽管正如Wakely指出的那样,这很可能是核心语言问题).
I actually think this is a gcc bug (84832 is closely related, though as Wakely notes it's possible that this should be a core language issue).
来自 [namespace.udecl]/15 :
当 using-declarator 将基类中的声明带入派生类时,派生类中的成员函数和成员函数模板将覆盖和/或使用相同的成员函数和成员函数模板隐藏它们名称,参数类型列表,cv限定符和 ref-qualifier (如果有)在基类中(而不是冲突).此类隐藏或覆盖的声明被排除在 using-declarator 引入的声明集中.
When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declarator.
在 [dcl/fct]/5 :
使用以下规则确定函数的类型.每个参数的类型(包括函数参数包)都由其自己的 decl-specifier-seq 和 declarator 决定.在确定每个参数的类型之后,将类型为"T的数组"或功能类型为T的任何参数调整为指向T的指针".生成参数类型列表后,在形成函数类型时,将删除所有修改参数类型的顶级
cv-qualifiers .转换后的参数类型以及省略号或函数参数包的存在与否的结果列表是函数的 parameter-type-list .
The type of a function is determined using the following rules. The type of each parameter (including function parameter packs) is determined from its own decl-specifier-seq and declarator. After determining the type of each parameter, any parameter of type "array of T" or of function type T is adjusted to be "pointer to T". After producing the list of parameter types, any top-level cv-qualifiers modifying a parameter type are deleted when forming the function type. The resulting list of transformed parameter types and the presence or absence of the ellipsis or a function parameter pack is the function's parameter-type-list.
B::foo
和D::foo
具有相同的名称("foo"),参数类型列表([T]
),cv限定符(无)和ref限定符(无).因此,派生的那个隐藏了基础的那个.
B::foo
and D::foo
have the same name ("foo"), parameter-type-list ([T]
), cv-qualification (none), and ref-qualifier (none). Hence, the derived one hides the base one.
这篇关于SFINAE方法完全禁用clang中基类的模板方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!