enable_if的C++模板重载:g++和clang的行为不同
C++ Template overload with enable_if: different behaviour with g++ and clang
在解决基类的模板成员函数的重载期间,我观察到g++(5.2.1-23)和clang(3.8.0)之间的不同行为,使用-std=c++14
。
#include <iostream>
#include <type_traits>
struct Base
{
template <typename T>
auto a(T t) -> void {
std::cout<< "Falsen";
}
};
template <bool Bool>
struct Derived : public Base
{
using Base::a;
template <typename T, bool B = Bool>
auto a(T t) -> std::enable_if_t<B, void>
{
std::cout<< "Truen";
}
};
int main()
{
Derived<true> d;
d.a(1); // fails with g++, prints "true" with clang
Derived<false> d2;
d2.a(1); // fails with clang++, prints "false" with g++
}
对Derived<true>::a
的调用以g++失败,并显示以下消息:
test.cc: In function ‘int main()’:
test.cc:28:8: error: call of overloaded ‘a(int)’ is ambiguous
d.a(1);
^
test.cc:18:8: note: candidate: std::enable_if_t<B, void> Derived<Bool>::a(T) [with T = int; bool B = true; bool Bool = true; std::enable_if_t<B, void> = void]
auto a(T t) -> std::enable_if_t<B, void>
^
test.cc:7:8: note: candidate: void Base::a(T) [with T = int]
auto a(T t) -> void {
^
并且对CCD_ 3的调用失败,伴随着clang++,并显示以下消息:
test.cc:32:6: error: no matching member function for call to 'a'
d2.a(1);
~~~^
/usr/bin/../lib/gcc/x86_64-linux-gnu/5.2.1/../../../../include/c++/5.2.1/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with T = int, B = false]
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^
我的猜测是,他们对using Base::a;
的解释不同,在clang中没有考虑它,而在g++中(可能考虑得太多了)。我认为会发生的情况是,如果Derived
有true
作为参数,那么a()
的调用将被调度到Derived
的实现,而如果参数是false
,则调用将被分配到Base::a
。
他们都错了吗?谁是对的?我应该向谁提交错误报告?有人能解释一下发生了什么事吗?
感谢
从3.3.10/p3名称隐藏[basic.scope.hiding]:
在成员函数定义中,块中名称的声明scope隐藏具有相同名称见3.3.7派生类中成员的声明(第10条)隐藏同名参见10.2
还有7.3.3/p15使用声明[namespace.udcl]:
当using声明将基类中的名称带入派生中的类作用域、成员函数和成员函数模板派生类重写和/或隐藏成员函数和成员具有相同名称的函数模板、参数类型列表(8.3.5),基类中的cv限定符和ref限定符(如果有的话)而不是冲突)。[注意:对于使用命名构造函数,请参见12.9。--尾注][示例:
struct B { virtual void f(int); virtual void f(char); void g(int); void h(int); }; struct D : B { using B::f; void f(int); // OK: D::f(int) overrides B::f(int); using B::g; void g(char); // OK using B::h; void h(int); // OK: D::h(int) hides B::h(int) }; void k(D* p) { p->f(1); // calls D::f(int) p->f(’a’); // calls B::f(char) p->g(1); // calls B::g(int) p->g(’a’); // calls D::g(char) }
--结束示例]
这是在成员名称查找过程中解决的。因此,它在模板参数推导之前。因此,正如评论中正确提到的那样,无论SFINAE的判决如何,基本模板函数都是隐藏的。
因此CLANG是正确的,GCC是错误的。
相关文章:
- 奇怪的结构&GCC&clang(void*返回类型)
- 数据成员SFINAE的C++17测试:gcc vs clang
- 当我编译webrtc服务器时,Windows上只支持clang-cl
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- Clang bug?使用指针作为模板参数
- clang整洁10忽略了我的NOLINT命令
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 在clang++预处理器中确定gcc工具链版本
- 为什么 Clang 不允许"and"作为函数名称?
- 带有 -stdlib=libc++ 的 clang++ 9.0.1 找不到<optional>
- clang格式:宏的缩进
- CLANG 编译器 说:变量"PTR"可能未初始化
- clang格式:禁用排序包含
- 为什么lambda在clang上崩溃而不是在gcc上崩溃
- gcc和clang在表达式是否为常量求值的问题上存在分歧
- 循环展开 - G++ 与 Clang++
- 如何使用Clang/GCC在Mac上为C/C++设置VSCode
- 一位朋友将模板函数缩写为clang和gcc
- 类模板参数推导-clang和gcc不同