为什么使用 SFINAE 查找方法是否存在会失败并使用 std::vector::begin [英] Why using SFINAE to find if a method exists fails with std::vector::begin
问题描述
我正在寻找一种方法来检测模板类是否具有方法 begin
、end
和 resize
.
I'm looking for a way to detect if a template class has the methods begin
, end
and resize
.
我尝试了此答案的修改版本:
I tried a modified version of this 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
.不过,实现这些方法的用户定义类工作正常.
However this prints 0. What is funny is that this will work with cbegin
and cend
but not with begin
, end
and resize
. User defined classes implementing those methods works fine though.
我已经在 g++ 和 Visual Studio 19 中尝试过这个,我得到了相同的结果,所以这似乎与编译器或 STL 的实现无关.
I've tried this with both g++ and with Visual Studio 19 and I get the same results so this doesn't seem to be related to the compiler or the STL's implementation.
推荐答案
std::vector
有一个重载的begin
:一个重载是const
而另一个不是.
std::vector
has an oveloaded begin
: one overload is const
and the other one is not.
当您编写 &C::begin
时,编译器不知道要使用哪个重载,因此它将这种歧义视为错误,并被 SFINAE 检测到.
The compiler doesn't know which overload to use when you write &C::begin
, so it treats this ambiguity as an error, which gets detected by SFINAE.
与其形成一个指向 begin
的指针,不如直接调用它:
Instead of forming a pointer to begin
, just call it:
// ...
template <typename C> static one test( decltype(void(std::declval<C &>().begin())) * );
// ...
(如果不是很明显,如果你试图检测一个带参数的函数,你必须提供参数,例如 .resize(0)
(或者可能是 .resize(std::size_t{})
) 而不是 .resize()
.)
(In case it's not obvious, if you're trying to detect a function with parameters, you must provide arguments, e.g. .resize(0)
(or perhaps .resize(std::size_t{})
) instead of just .resize()
.)
这是另一个更短的解决方案:
And here's another, shorter solution:
#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
的奇特解决方案:
And here's a fancy C++20 requires
-based solution:
#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;
}
这篇关于为什么使用 SFINAE 查找方法是否存在会失败并使用 std::vector::begin的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!