Pre*_*nik 7 c++ move-semantics perfect-forwarding c++11 template-argument-deduction
假设我有一些函数是一个类型的参数类型(或几个参数类型),我想推断出它.我也希望基于rvalue或lvalue这一事实的不同行为.直接写出它会导致一个明显的(对于有经验的人)陷阱,因为完美的转发:
#include <iostream>
#include <vector>
template <typename T>
void f (T &&v) // thought to be rvalue version
{
// some behavior based on the fact that v is rvalue
auto p = std::move (v);
(void) p;
}
template <typename T>
void f (const T &v) // never called
{
auto p = v;
(void) p;
}
int main ()
{
std::vector<int> x = {252, 135};
auto &z = x;
f (z);
std::cout << x.size () << '\n'; // woah, unexpected 0 or crash
}
Run Code Online (Sandbox Code Playgroud)
即使这种行为的偷偷摸摸的性质已经是一个有趣的点,但我的问题实际上是不同的 - 对于这种情况,什么是好的,简洁的,可理解的解决方法?
如果没有推断出完美转发的类型(例如,它已经是外层类的模板参数或类似的东西),那么众所周知的解决方法是使用typename identity<T>::type&&而不是T&&因为相同的结构是避免类型推导的解决方法,它在这种情况下没有帮助.我可以想象一些解决它的技巧,但代码清晰度可能会被破坏,它看起来与类似的非模板函数完全不同.
隐藏在模板参数列表中的SFINAE:
#include <type_traits>
template <typename T
, typename = typename std::enable_if<!std::is_lvalue_reference<T>{}>::type>
void f(T&& v)
{
}
template <typename T>
void f(const T& v)
{
}
Run Code Online (Sandbox Code Playgroud)
隐藏在返回类型语法中的SFINAE:
template <typename T>
auto f(T&& v)
-> typename std::enable_if<!std::is_lvalue_reference<T>{}>::type
{
}
template <typename T>
void f(const T& v)
{
}
Run Code Online (Sandbox Code Playgroud)
在C++中,14 typename std::enable_if<!std::is_lvalue_reference<T>{}>::type可以缩短为:
std::enable_if_t<!std::is_lvalue_reference<T>{}>
Run Code Online (Sandbox Code Playgroud)
无论如何,即使在C++ 11中,如果你发现它更简洁,你可以使用别名模板缩短语法:
template <typename T>
using check_rvalue = typename std::enable_if<!std::is_lvalue_reference<T>{}>::type;
Run Code Online (Sandbox Code Playgroud)