Clang 无法从基类中找到 const 模板成员函数

Clang fails to find const template member function from base class

本文关键字:const 成员 函数 基类 Clang      更新时间:2023-10-16

以下C++文件:

struct Base {
template <typename T, int = 42>
void f(T &&) const {}
};
struct Derived: Base {
template <typename T, typename X = typename T::asdf>
void f(T &&) const {}
using Base::f;
};
int main() {
Derived const cd;
cd.f('x');
}

使用GCC 编译良好,但不能使用 Clang:

$ g++-7.3.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-7.2.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-6.4.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-5.4.0 -std=c++11 test.cpp -o test -Wall -Wextra
$ g++-4.9.4 -std=c++11 test.cpp -o test -Wall -Wextra
$ clang++-4.0 -std=c++11 test.cpp -o test -Wall -Wextra
test.cpp:15:12: error: no matching member function for call to 'f'
cd.f('x');
~~~^
test.cpp:8:14: note: candidate template ignored: substitution failure [with T = char]: type 'char' cannot be used prior to '::' because it has no members
void f(T &&) const {}
^
1 error generated.
$ clang++-5.0 -std=c++11 test.cpp -o test -Wall -Wextra
test.cpp:15:12: error: no matching member function for call to 'f'
cd.f('x');
~~~^
test.cpp:8:14: note: candidate template ignored: substitution failure [with T = char]: type 'char' cannot be used prior to '::' because it has no members
void f(T &&) const {}
^
1 error generated.
$ clang++-6.0 -std=c++11 test.cpp -o test -Wall -Wextra
test.cpp:15:12: error: no matching member function for call to 'f'
cd.f('x');
~~~^
test.cpp:8:14: note: candidate template ignored: substitution failure [with T = char]: type 'char' cannot be used prior to '::' because it has no members
void f(T &&) const {}
^
1 error generated.

为什么它不使用 Clang 编译?我的代码正确吗?这是编译器错误吗?C++标准中的错误?

我认为这是一个 gcc 错误。

根据using-declarator(强调我的):

[命名空间.udecl]

using-declarator

引入的声明集是通过对 using-declarator 中的名称执行限定名称查找 ([basic.lookup.qual], [class.member.lookup]) 来查找的,不包括如下所述隐藏的函数。

当 using-declarator 将基类中的声明引入派生类时,派生类中的成员函数和成员函数模板将覆盖和/或隐藏基类中具有相同名称、参数类型列表、cv 限定符和 ref 限定符(如果有)的成员函数和成员函数模板(而不是冲突)。此类隐藏或重写的声明将从 using-声明符引入的声明集中排除。

在您的情况下,基类f()应该是隐藏的,并且对派生类不可见。

另一个重要的一点是,using的效果是在名称查找阶段,在SFINAE之前。因此,是否有SFINAE没有影响。