如何解决为什么使用SFINAE查找是否存在方法,但std :: vector :: begin失败
我正在寻找一种检测模板类是否具有方法begin
,end
和resize
的方法。
我尝试过对此answer进行修改:
#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
和cend
一起使用,而不与begin
,end
和resize
一起使用。用户定义的类可以实现这些方法,但是效果很好。
我已经使用g ++和Visual Studio 19进行了尝试,并且得到了相同的结果,因此这似乎与编译器或STL的实现无关。
解决方法
std::vector
包含一个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;
}
这是一个基于C ++ 20 requires
的奇妙解决方案:
#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;
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。