aki*_*kim 24 c++ auto return-type-deduction c++14
感谢decltype
作为返回类型,C++ 11使得引入装饰器非常容易.例如,考虑这个类:
struct base
{
void fun(unsigned) {}
};
Run Code Online (Sandbox Code Playgroud)
我想用其他功能来装饰它,因为我会用不同种类的装饰做几次,所以我首先介绍一个decorator
简单地转发所有内容的课程base
.在真实的代码中,这是通过以下方式完成的,std::shared_ptr
这样我就可以删除装饰并恢复"裸"对象,并且所有内容都是模板化的.
#include <utility> // std::forward
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
Run Code Online (Sandbox Code Playgroud)
完美的转发,decltype
真是太棒了.在实际代码中,我实际上使用的是一个只需要函数名称的宏,其余的都是样板文件.
然后,我可以引入一个derived
为我的对象添加功能的类(derived
不正确,同意,但它有助于理解这derived
是一种base
,虽然不是通过继承).
struct foo_t {};
struct derived : decorator
{
using decorator::fun; // I want "native" fun, and decorated fun.
void fun(const foo_t&) {}
};
int main()
{
derived d;
d.fun(foo_t{});
}
Run Code Online (Sandbox Code Playgroud)
然后C++ 14带来了返回类型推导,它允许以更简单的方式编写内容:删除decltype
转发函数的一部分:
struct decorator
{
base b;
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
Run Code Online (Sandbox Code Playgroud)
并且然后它打破.是的,至少根据GCC和Clang的说法,这个:
template <typename... Args>
auto
fun(Args&&... args)
-> decltype(b.fun(std::forward<Args>(args)...))
{
return b.fun(std::forward<Args>(args)...);
}
};
Run Code Online (Sandbox Code Playgroud)
不等于这个(问题不是auto
与decltype(auto)
):
template <typename... Args>
auto
fun(Args&&... args)
{
return b.fun(std::forward<Args>(args)...);
}
};
Run Code Online (Sandbox Code Playgroud)
重载决议似乎完全不同,它结束如下:
clang++-mp-3.5 -std=c++1y main.cc
main.cc:19:18: error: no viable conversion from 'foo_t' to 'unsigned int'
return b.fun(std::forward<Args>(args)...);
^~~~~~~~~~~~~~~~~~~~~~~~
main.cc:32:5: note: in instantiation of function template specialization
'decorator::fun<foo_t>' requested here
d.fun(foo_t{});
^
main.cc:7:20: note: passing argument to parameter here
void fun(unsigned) {}
^
Run Code Online (Sandbox Code Playgroud)
我理解失败:我的call(d.fun(foo_t{})
)与签名完全不匹配derived::fun
,这需要a const foo_t&
,所以非常渴望decorator::fun
踢(我们知道如何Args&&...
非常不耐烦地绑定到任何完全不匹配的东西).所以它转发给了无法解决的base::fun
问题foo_t
.
如果我derived::fun
改为采取foo_t
代替const foo_t&
,那么它按预期工作,这表明确实在这里问题是derived::fun
和之间存在竞争decorator::fun
.
然而,为什么这个显示与返回类型扣除??? 更确切地说,为什么委员会选择了这种行为?
为了让事情更容易,在Coliru:
谢谢!
Naw*_*waz 18
看看这个电话:
d.fun(foo_t{});
Run Code Online (Sandbox Code Playgroud)
您创建一个临时(即右值),将其作为参数传递给函数.那你觉得怎么样?
它首先尝试绑定到参数Arg&&
,因为它可以接受rvalue 但 由于无效的返回类型推导(由于foo_t
无法转换为unsigned int
,因此原因b.fun(std::forward<Args>(args)...)
是无效表达式),如果使用decltype(expr)
as ,则拒绝此函数返回类型,在这种情况下SFINAE进入图片.但是如果你简单地使用auto
,那么SFINAE就不会出现,并且错误被归类为硬错误,导致编译失败.
foo_t const&
如果SFINAE在第一种情况下工作,则调用接受作为参数的第二个重载.