尝试使用完美转发,我遇到了模板扣除的问题。
以下编译
template<typename T>
void forwarder(T&& x)
{
}
int main()
{
int x = 42;
forwarder(x);
return 0;
}
虽然如果我将const
添加到模板化函数的签名中,则不会。
template<typename T>
void forwarder(const T&& x) // adding const here
{
}
int main()
{
int x = 42;
forwarder(x);
return 0;
}
来自g++
test.cc: In function ‘int main()’:
test.cc:11:16: error: cannot bind ‘int’ lvalue to ‘const int&&’
test.cc:4:6: error: initializing argument 1 of ‘void forwarder(const T&&) [with T = int]’
我可以通过指定int&
作为模板参数来实现它:forwarder<int&>(x)
我认为即使在模板中添加const
也许会有用,但是在尝试了一些严重的失败之后我的头疼了。
对模板演绎有深刻理解的人能否告诉我这里发生了什么?使用带模板演绎的const是否可行且实用?
答案 0 :(得分:0)
最好使用类型特征和标签分派来选择特定的过载:
template<typename T>
void forwarder_impl(T&& x, std::true_type, std::true_type)
{
std::cout << "rvalue reference to const\n";
}
template<typename T>
void forwarder_impl(T&& x, std::true_type, std::false_type)
{
std::cout << "rvalue reference to non-const\n";
}
template<typename T>
void forwarder_impl(T&& x, std::false_type, std::true_type)
{
std::cout << "lvalue reference to const\n";
}
template<typename T>
void forwarder_impl(T&& x, std::false_type, std::false_type)
{
std::cout << "lvalue reference to non-const\n";
}
template<typename T>
void forwarder(T&& x)
{
forwarder_impl(
std::forward<T>(x),
typename std::is_rvalue_reference<decltype(x)>::type(),
typename std::is_const<typename std::remove_reference<decltype(x)>::type>::type()
);
}
int main()
{
const int x = 42;
int y = 42;
forwarder(std::move(x));
forwarder(std::move(y));
forwarder(x);
forwarder(y);
}
输出:
rvalue reference to const
rvalue reference to non-const
lvalue reference to const
lvalue reference to non-const
为什么你想做到这一点仍然是一个谜。
如果您想限制forwarder
仅接受对const的引用,您可以使用SFINAE来保留T&&
的普遍性:
template<typename T>
typename std::enable_if<
std::is_const<typename std::remove_reference<T>::type>::value
>::type
forwarder(T&& x)
{
auto value_cat = std::is_rvalue_reference<decltype(x)>::value ? "r" : "l";
std::cout << value_cat << "value reference to const\n";
}
int main()
{
const int x = 42;
forwarder(std::move(x));
forwarder(x);
//int y = 42;
//forwarder(std::move(y)); //compile-time error
//forwarder(y); //compile-time error
}
输出:
rvalue reference to const
lvalue reference to const
http://ideone.com/t5UoZE http://ideone.com/jc2Ek2
再一次,这种事情的动机超出了我的范围。
资源:https://www.google.com/search?q=scott+meyers+universal+references