template<typename T> struct wrapper: T { using T::foo; template<typename Arg> auto foo(Arg) const -> std::enable_if_t<not std::is_constructible<Arg>::value,bool> { return false; } }; struct bar { template<typename Arg> auto foo(Arg) const -> bool { return true; } };
在这个简单的例子中,包装器只有在基类不可行的情况下才添加一个重载的foo(我简化了std :: enable_if到最简单的事情;原来的一个涉及检测成语).但是,g和clang不同意.请注意以下几点:
int main() { assert(wrapper<bar>{}.foo(0)); }
g是可以的:包装上的foo< bar>是SFINAE出来,所以它使用一个从bar而不是.另一方面,clang++ seems to assume的包装< bar> :: foo总是阴影吧:: foo,即使SFINAEd出来.这是错误信息:
06002
解决方法
In the declaration set,using-declarations are replaced by the set of
designated members that are not hidden or overridden by members of the
derived class (7.3.3),
和§7.3.3
When a using-declaration brings names from a base class into a derived class scope,[…] member function templates in the derived class override and/or hide member functions and member function templates with the same name,parameter-type-list (8.3.5 [dcl.fct]),cv-qualification,and ref-qualifier (if any) in a base class (rather than conflicting).
显然,您的示例中唯一的区别在于返回类型.因此,Clang是正确的,并且GCC被窃取.
这个措辞是由CWG #1764提出的:
According to 7.3.3 [namespace.udecl] paragraph 15,
When a using-declaration brings names from a base class into a derived class scope,[…]
10.2中给出了类范围名称查找的算法
[class.member.lookup],但是,没有实现这个要求;
没有什么可以删除隐藏的基类成员(替换)
结果集中的使用声明,第3段).该决议于2014年2月移交给DR,所以GCC也没有实施.
正如@ TartanLlama的回答中提到的,你可以介绍一个对手来处理其他情况.沿线的东西
template <typename Arg,typename=std::enable_if_t<std::is_constructible<Arg>{}>> decltype(auto) foo(Arg a) const { return T::foo(a); }Demo.