为什么使用 SFINAE 查找方法是否存在会失败并使用 std::vector::begin [英] Why using SFINAE to find if a method exists fails with std::vector::begin

查看:54
本文介绍了为什么使用 SFINAE 查找方法是否存在会失败并使用 std::vector::begin的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种方法来检测模板类是否具有方法 beginendresize.

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.有趣的是,这适用于 cbegincend 但不适用于 begin, endresize.不过,实现这些方法的用户定义类工作正常.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆