Mor*_*enn 11 c++ sfinae shadowing language-lawyer c++11
在遇到另一个设计的问题之后,我决定make make一个包装类来向基类的某些成员函数添加重载,当且仅当基类中不存在可行的重载时.基本上,这是我想要做的:
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;
}
};
Run Code Online (Sandbox Code Playgroud)
在这个简单的例子中,只有当基类中的那个不可行时才wrapper添加一个重载foo(我简化std::enable_if为最简单的东西;原始的一个涉及检测习语).但是,g ++和clang ++不同意.请考虑以下事项main:
int main()
{
assert(wrapper<bar>{}.foo(0));
}
Run Code Online (Sandbox Code Playgroud)
g ++没关系:foofrom wrapper<bar>是SFINAEd,所以它使用的是bar相反的.在另一方面,铛++似乎假定是 wrapper<bar>::foo 永远的阴影bar::foo,即使SFINAEd出来.这是错误消息:
Run Code Online (Sandbox Code Playgroud)main.cpp:30:26: error: no matching member function for call to 'foo' assert(wrapper<bar>{}.foo(0)); ~~~~~~~~~~~~~~~^~~ /usr/include/assert.h:92:5: note: expanded from macro 'assert' ((expr) \ ^ /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/5.2.0/../../../../include/c++/5.2.0/type_traits:2388:44: note: candidate template ignored: disabled by 'enable_if' [with Arg = int] using enable_if_t = typename enable_if<_Cond, _Tp>::type; ^ 1 error generated.
那么,谁是对的?这个代码应该像clang ++一样被拒绝,还是应该工作和调用bar::foo?
考虑§10.2:
在声明集中,using-declaration被替换为派生类成员(7.3.3)未隐藏或覆盖的指定成员集,
§7.3.3去了
当using声明将基类中的名称带入派生类范围时,派生类中的成员函数模板覆盖和/或隐藏具有相同名称的成员函数和成员函数模板,parameter-type-list(8.3基类中的.5 [dcl.fct]),cv-qualification和ref-qualifier(如果有的话)(而不是冲突的).
显然,您的示例中唯一的区别在于返回类型.因此,Clang是正确的,并且GCC被窃听.
CWG#1764引入了措辞:
根据7.3.3 [namespace.udecl]第15段,
当using声明将基类中的名称带入派生类范围时,[...]
但是,10.2 [class.member.lookup]中给出的类范围名称查找算法没有实现此要求.没有任何东西可以从结果集中删除隐藏的基类成员(将第3段中的using声明替换).
该决议于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);
}
Run Code Online (Sandbox Code Playgroud)
演示.
| 归档时间: |
|
| 查看次数: |
172 次 |
| 最近记录: |