从C 模板中的非const l值参考中推导const l值参考
Deducing a const l-value reference from a non-const l-value reference in C++ template
假设您有以下功能:
void f(const int&) {
// Do something, making a copy of the argument.
}
void f(int&&) {
// Do the same thing, but moving the argument.
}
它们是相当多的多余的 - 功能是复制还是移动论点之间的唯一区别。当然,我们可以通过将其重写为单个模板函数来做得更好:
template<typename T>
void g(T&&) {
// Do something, possibly using std::forward to copy or move the argument.
}
这有效,是实践中常用的成语。但是模板可以将模板实例化为三个函数,与上面的两个函数。我们可以通过以下代码来验证这一点:
#include <iostream>
template<typename T> constexpr char *type = nullptr;
template<> constexpr const char *type<int&> = "int&";
template<> constexpr const char *type<const int&> = "const int&";
template<> constexpr const char *type<int> = "int";
template<typename T>
void g(T&&) {
std::cout << reinterpret_cast<void*>(&g<T>)
<< " = &g<" << type<T> << ">" << std::endl;
}
int main() {
int i = 0;
const int& cr = 0;
g(i);
g(cr);
g(0);
return 0;
}
/*
Prints:
0x100f45080 = &g<int&>
0x100f45100 = &g<const int&>
0x100f45180 = &g<int>
*/
这已经为T = int&
的情况添加了第三个功能,当我们使用上面的非预测函数f
时,这是我们没有的。在这种情况下,我们实际上并不需要该函数的非计算L值参考版本(构建的f
足以满足我们的原始需求),而这会增加代码的大小,尤其是当我们编写了许多模板函数时,互相打电话的方式。
有没有办法在上面编写我们的函数g
,以便编译器在我们的示例代码中调用g(i)
时自动推论T = const int&
?即,我们不必手动编写g<const int&>(i)
但仍然得到所需的行为的方式。
这是一个主观的观点,可以说"正向引用"("通用引用")比专用的过载更好。当然,在很多情况下,这是真的,但是如果您想完全控制,他们将不会完成所有工作。
您可以通过添加
来明确确保用户不会通过非const lvalue参考 static_assert(!std::is_lvalue_reference<T>::value || std::is_const<typename std::remove_reference<T>::type>::value, "only call g with const argument");
内部G,但这并不是在所有情况下是一个很好的解决方案。
否则您要为vector :: push_back(...)做的事情并提供显式过载 - 但这是您的起点,请参见https://en.cppreference.com/w/cpp/container/vector/推回。
"正确"的答案仅取决于您的要求。
编辑:@sjoerd的建议看起来像:
template <typename T>
class aBitComplicated {
public:
void func(T&& v) { internal_func(std::forward<T>(v)); }
void func(const T& v) { internal_func(v); }
private:
template <typename U>
void internal_func(U&& v) { /* your universal code*/ }
};
也有一些更复杂/复杂的版本,但这应该是最简单的版本,可以实现您所要求的。
相关文章:
- 通用参考 l 值不复制对象
- 是否有必要使用 std::move?这不是已经是一个右值参考了吗?
- Lambda闭包左值可以作为右值参考参数传递
- 如何获取地图值的参考?
- 演绎指南中的参考文献和值之间的差异
- 赋值运算符的返回值可以作为参考吗?
- 如果值来自成员变量,则复制初始化和参考初始化之间的C 差异
- 超载函数既不按值,也不是通过参考来对象,而是将撤销的指针换成对象
- 移动 l 值参考参数是否是一种不好的做法?
- C 按值返回与参考返回
- 为什么未调用具有常量参考返回值的超载方法
- 是否有一种方法可以始终通过值(制作副本)而不是在使用类成员函数时通过参考来传递
- 作为RVALUE参考与双移动值的传递
- 可以std ::移动引起切片时切入L值参考
- 为什么通用参考和右值参考的流量不同
- 提供功能版本,其中可用值和参考
- 通过值和参考,对象构建返回对象之间的区别
- 按值传递参考参数
- C 模板函数基于参数是值还是参考
- 使用具有默认值的参考参数是一种良好的做法