面试题答案
一键面试- 误区分析:
- 在这段代码中,
customMove
模板函数使用std::enable_if
尝试限制只有非const
类型的对象才能使用该函数进行移动。然而,在main
函数中,创建了一个const MyType
对象obj
,并试图调用customMove(obj)
。由于obj
是const
类型,根据std::enable_if
的条件,customMove
函数对于const MyType
类型应该是不可用的。但实际情况是,编译器并不会报错,因为std::enable_if
在此处的使用存在问题。这里的std::enable_if
应该是用于模板函数的返回类型,当条件不满足时,会导致模板函数的重载决议失败,从而使该函数不可用。但对于const MyType
类型,编译器并没有找到合适的customMove
函数重载,却没有给出编译错误,这是因为std::enable_if
的使用位置和方式导致编译器没有正确处理这种情况。 - 从类型推导角度看,
customMove
函数期望接收一个T&
类型的参数,而const MyType
类型不能隐式转换为MyType&
,但由于std::enable_if
的错误使用,编译器没有正确阻止这种非法调用。 - SFINAE(Substitution Failure Is Not An Error)原理在此处没有正确应用。
std::enable_if
应该使不满足条件的模板函数在重载决议阶段被忽略,而不是在调用时导致未定义行为或编译错误不明显。
- 在这段代码中,
- 改进方案:
- 可以将
std::enable_if
应用到模板参数列表中,这样当类型为const
时,模板函数将在重载决议阶段被忽略。修改后的代码如下:
- 可以将
#include <iostream>
#include <type_traits>
template <typename T, typename = std::enable_if_t<!std::is_const<T>::value>>
T&& customMove(T& obj) {
return std::move(obj);
}
class MyType {
public:
int data;
MyType(int d) : data(d) {}
};
int main() {
const MyType obj(10);
// 此处编译时会报错,提示找不到合适的customMove函数
// auto movedObj = customMove(obj);
MyType nonConstObj(20);
auto movedNonConstObj = customMove(nonConstObj);
return 0;
}
- 在上述改进后的代码中,
std::enable_if_t<!std::is_const<T>::value>
作为模板的默认模板参数。当T
是const
类型时,模板参数推导失败,根据 SFINAE 原则,该customMove
函数在重载决议阶段被忽略,编译器会提示找不到合适的函数来调用customMove(obj)
(其中obj
为const MyType
类型)。而对于非const
类型的对象,customMove
函数可以正常工作,正确地移动对象。