c++ - 为什么使用 SFINAE 查找方法是否存在因 std::vector::begin 失败
问题描述
我正在寻找一种方法来检测模板类是否具有方法begin
,end
和resize
。
我尝试了这个答案的修改版本:
#include <iostream>
#include <vector>
// SFINAE test
template <typename T>
class has_method
{
typedef char one;
struct two { char x[2]; };
template <typename C> static one test( decltype(&C::begin) ) ;
template <typename C> static two test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(char) };
};
int main(int argc, char *argv[])
{
std::cout << has_method<std::vector<int>>::value << std::endl;
return 0;
}
但是,这会打印 0。有趣的是,这将适用于cbegin
andcend
但不适用于begin
, end
and resize
。实现这些方法的用户定义类工作正常。
我用 g++ 和 Visual Studio 19 都试过了,我得到了相同的结果,所以这似乎与编译器或 STL 的实现无关。
解决方案
std::vector
有一个 oveloaded begin
:一个重载是const
,另一个不是。
当您编写 时,编译器不知道要使用哪个重载&C::begin
,因此它将这种歧义视为错误,由 SFINAE 检测到。
而不是形成一个指向 的指针begin
,只需调用它:
// ...
template <typename C> static one test( decltype(void(std::declval<C &>().begin())) * );
// ...
(如果不是很明显,如果您尝试检测带有参数的函数,则必须提供参数,例如.resize(0)
(或可能.resize(std::size_t{})
)而不是仅提供参数.resize()
。)
这是另一个更短的解决方案:
#include <iostream>
#include <vector>
template <typename T, typename = void>
struct has_begin : std::false_type {};
template <typename T>
struct has_begin<T, decltype(void(std::declval<T &>().begin()))> : std::true_type {};
int main(int argc, char *argv[])
{
std::cout << has_begin<std::vector<int>>::value << std::endl;
}
这是一个requires
基于 C++20 的精美解决方案:
#include <iostream>
#include <vector>
template <typename T>
concept has_begin = requires(T t) {t.begin();};
int main(int argc, char *argv[])
{
std::cout << has_begin<std::vector<int>> << std::endl;
}
推荐阅读
- git - 使用 Git 存储库签入/签出 Visual Studion Team 项目
- c# - ASP.NET 会话 cookie、CSRF 令牌和 Ajax 调用的奇怪行为
- python - 熊猫 groupby 之后的 for 循环
- python - 使用机械化登录
- python - Keras 中的“淡入”新层
- s4sdk - 使用 UserAccessor 访问用户属性
- sql-server - 使用T-SQL执行SSIS包不返回任何结果
- amazon-web-services - 尝试使用弹性豆茎运行时出现 Prisma 错误
- watson-iot - wiotp out Raspberry Pi 上的 Node-RED 节点连接到 Watson IoT 并在流量更改后保持断开连接
- ios - 如何根据多个选项过滤json数组