如何使用类型特征将函数的通用引用参数限制为 r 值引用?
How can I use type traits to limit the universal reference parameters of a function to r-value references?
我想定义一个具有通用引用参数的函数op2()
。
根据类型,我想进一步区分op2()
中的函数参数是否是类型test
的 r 值引用。 如果是这种情况,我想将op2
的返回类型定义为int
。 在所有其他情况下,返回类型应为void
。
这是我的我:
#include <type_traits>
#include <iostream>
#include <string>
class test {
public:
test(const std::string& str) : _str(str){}
test(test&& t) = default;
test(const test& t) = default;
friend std::ostream& operator<<(std::ostream& os, test&& t) {
os << t._str;
return os;
}
private:
std::string _str;
};
template<typename T>
void op(T&& x) {
std::cout << " is rvalue ref? " << std::is_rvalue_reference<decltype(x)>::value << std::endl;
std::cout << " is a test rvalue ref? " << std::is_same<test&&, decltype(x)>::value << std::endl;
std::cout << std::forward<T>(x) << std::endl;
}
template<typename T> // This is A
typename std::enable_if<std::negation<std::conjunction<std::is_same<test, T>, std::is_rvalue_reference<T>>>::value>::type op2(T&& x) {
std::cout << "op2: A: " << std::forward<T>(x) << std::endl;
}
template<typename T> // This is B
typename std::enable_if<std::conjunction<std::is_same<test, T>, std::is_rvalue_reference<T>>::value, int>::type op2(T&& x) {
std::cout << "op2: B: " << std::move(x) << std::endl;
return EXIT_SUCCESS;
}
int main() {
op(std::string{"r-value string"});
std::string str{"l-value string"};
op(str);
op(test{"test"});
op2(std::string{"r-value string"}); //gets into A
op2(str); //gets into A
op2(test{"r-value string"}); //Should get into B, but actually gets into A
}
代码的问题在于,最后一个op2()
调用进入错误的重载。
我尝试了另一个函数,op()
它通过decltype()
获得正确的类型,但我不知道如何在类型特征中使用decltype()
。
我正在使用 C++17 和 gcc8.2
转发引用T&&
永远不会将其模板参数T
推断为右值引用类型。如果参数是类型为test
的右值,则T
将被推导出为test
,而如果参数是test
类型的左值,则T
将被推导为test&
。
因此,重载应重写为:
template<typename T>
std::enable_if_t<!std::is_same_v<test, T>, void> op2(T&& x) {
std::cout << "op2: A: " << std::forward<T>(x) << std::endl;
}
template<typename T>
std::enable_if_t<std::is_same_v<test, T>, int> op2(T&& x) {
std::cout << "op2: B: " << std::move(x) << std::endl;
return EXIT_SUCCESS;
}
要在只有类型时使用decltype
,您必须使用std::declval
:
decltype(std::declval<T>())
但是你总是会从中获得一个右值引用,所以这不是你想要的。相反,请利用转发引用推导的类型。 如果传入右值,T
将不是引用,并且将是左值的T&
。
这意味着您可以将 B 修改为:
template<typename T>
std::enable_if_t<std::is_same_v<test, T>, int> op2(T&& x);
因为如前所述,如果您传入类型test
的右值,T
将被推导出为test
。
在您的情况下,简单的重载更简单:
template<typename T>
void op2(T&& x) { // This is A
std::cout << "op2: A: " << std::forward<T>(x) << std::endl;
}
int op2(test&& x) { // This is B
std::cout << "op2: B: " << std::move(x) << std::endl;
return EXIT_SUCCESS;
}
演示
相关文章:
- 将const引用参数初始化为默认参数会导致悬空引用吗
- 具有常量引用参数的函数模板专用化
- C++:常量引用参数
- 字符串引用参数的效率C++
- 通过非常量引用参数修改常量引用参数
- 如何将指针变量作为引用参数传递?
- C++初始化 std::function 时如何将占位符绑定到引用/引用参数?
- 移动类的成员作为常量引用参数传递
- C++带有适用于左值和右值的引用参数的函数
- constexpr 函数的常量引用参数:gcc/msvc vs clang/icc
- 如何使用类型特征将函数的通用引用参数限制为 r 值引用?
- 委托构造函数和引用参数
- 对 const 引用参数使用默认值会导致崩溃
- 为什么我们不允许将纯引用参数传递给 std::thread,但允许传递原始指针?
- 为什么我需要将默认引用参数定义为 const 以便为其分配一个左值?
- 将非左值作为常量引用参数传递.临时是在本地作用域还是在调用方作用域中创建的?
- 如何强制函数仅接受左值引用参数
- 模板引用参数推断失败C++
- 非类型引用参数可以在运行时修改,这是否意味着模板可以在运行时实例化?
- 将unique_ptr作为引用参数或常量传递unique_ptr引用