[英]Why using SFINAE to find if a method exists fails with 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
和cend
但与begin
, end
和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;
}
这是一个花哨的 C++20 requires
-based 解决方案:
#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;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.