gpt4 book ai didi

c++ - 如何使用SFINAE检测类的存在?

转载 作者:IT老高 更新时间:2023-10-28 12:50:13 25 4
gpt4 key购买 nike

是否可以使用SFINAE检测C++中是否存在类?如果可能的话怎么办?

假设我们有一个仅由某些版本的库提供的类。我想知道是否可以使用SFINAE来检测该类是否存在。检测结果是任意的,如果存在,则枚举常量为1,否则为0。

最佳答案

如果我们要求编译器告诉我们有关类类型T的任何信息,而该类类型没有
甚至被声明,我们势必会收到编译错误。没有办法
在那附近。因此,如果我们想知道类T是否“存在”,那么T在哪里
甚至可能尚未声明,我们必须先声明T

但这没关系,因为仅声明T不会使其“存在”,因为T必须存在的意思是T已定义。如果声明了T
然后,您可以确定它是否已经定义,您无需进入
任何困惑。

因此,问题在于确定T是否为已定义的类类型。
sizeof(T)在这里没有帮助。如果T未定义,它将给出一个incomplete type T错误。同样是typeid(T)。也没有好处
根据T *类型定义SFINAE探针,因为T *是已定义的类型
只要声明了T,即使没有声明T。既然我们是
必须声明类Tstd::is_class<T>不是
回答任何一个,因为该声明只要说"is"就足够了。

C++ 11在std::is_constructible<T ...Args>中提供了<type_traits>。能够
这提供了一个现成的解决方案? -如果已定义T,则它必须至少具有一个构造函数。

恐怕不是。如果您知道至少一个公众的签名T的构造函数,那么GCC的<type_traits>(自4.6.3起)确实可以
这生意。假设一个已知的公共(public)构造函数是T::T(int)。然后:

std::is_constructible<T,int>::value

如果定义了 T,则为true;如果仅声明 T,则为false。

但这不是便携式的。如果未定义 <type_traits>,则VC++ 2010中的 std::is_constructible尚不提供 std::has_trivial_constructor<T>,甚至其 T也将阻塞:很有可能,当 std::is_constructible到达时,它也将随之效仿。此外,如果最终只有 T的私有(private)构造函数提供给 std::is_constructible,那么甚至是GCC
将呕吐(这是扬眉)。

如果定义了 T,则它必须具有一个析构函数,并且只有一个析构函数。而且该析构函数比 T的任何其他可能成员更可能公开。有鉴于此,我们可以做的最简单,最有效的方法就是为 T::~T的存在制作一个SFINAE探针。

该SFINAE探针无法通过常规方式确定 T是否具有普通成员函数 mf-使"is"过载
SFINAE探测函数的“”接受一个用术语定义的参数
类型 &T::mf。因为我们不允许使用a的地址
析构函数(或构造函数)。

但是,如果定义了 T,则 T::~T的类型为 DT-必须为
只要 decltype(dt)是计算结果为
调用 dt;因此 T::~T也将是一种类型,
原则作为函数重载的参数类型给出。因此,我们
可以这样编写探针(GCC 4.6.3):
#ifndef HAS_DESTRUCTOR_H
#define HAS_DESTRUCTOR_H

#include <type_traits>

/*! The template `has_destructor<T>` exports a
boolean constant `value that is true iff `T` has
a public destructor.

N.B. A compile error will occur if T has non-public destructor.
*/
template< typename T>
struct has_destructor
{
/* Has destructor :) */
template <typename A>
static std::true_type test(decltype(std::declval<A>().~A()) *) {
return std::true_type();
}

/* Has no destructor :( */
template<typename A>
static std::false_type test(...) {
return std::false_type();
}

/* This will be either `std::true_type` or `std::false_type` */
typedef decltype(test<T>(0)) type;

static const bool value = type::value; /* Which is it? */
};

#endif // EOF

仅限制 DT *必须具有一个公共(public)析构函数才能在 T的参数表达式中合法调用。 ( decltype(std::declval<A>().~A())是我贡献了 here的方法自省(introspection)模板的简化改编。)

该参数表达式 has_destructor<T>的含义对于某些语言(尤其是 std::declval<A>().~A())可能是晦涩的。函数模板 std::declval<A>()是在 std::declval<T>()中定义的,并返回 <type_traits>(对 T&&的右值引用)-尽管只能在未评估的上下文中调用它,例如 T的参数。因此 decltype的含义是在给定的 std::declval<A>().~A()上调用 ~A()A在这里通过消除对 std::declval<A>()的任何公共(public)构造函数的需要或使我们知道这一点而对我们很有帮助。

因此,“Yes重载”的SFINAE探针的参数类型是:指向 T的析构函数的类型的指针,并且 A将匹配该重载,以防万一存在诸如 test<T>(0)的析构函数的类型,例如 A = A

掌握了 T并牢记其对 has_destructor<T>的可公开破坏值的局限性,您可以通过在询问问题之前确保对其进行声明,来测试是否在代码的某个点定义了 T类。这是一个测试程序。
#include "has_destructor.h"
#include <iostream>

class bar {}; // Defined
template<
class CharT,
class Traits
> class basic_iostream; //Defined
template<typename T>
struct vector; //Undefined
class foo; // Undefined

int main()
{
std::cout << has_destructor<bar>::value << std::endl;
std::cout << has_destructor<std::basic_iostream<char>>::value
<< std::endl;
std::cout << has_destructor<foo>::value << std::endl;
std::cout << has_destructor<vector<int>>::value << std::endl;
std::cout << has_destructor<int>::value << std::endl;
std::count << std::has_trivial_destructor<int>::value << std::endl;
return 0;
}

使用GCC 4.6.3构建,这将告诉您2个 T
具有析构函数,而2个 // Defined类则没有。第五
输出行将表明 // Undefined是可破坏的,最后
行将显示 int同意。如果我们要
要将字段缩小为类类型,可以在之后应用 std::has_trivial_destructor<int>我们确定 std::is_class<T>是可破坏的。

Visual C++ 2010不提供 T。支持该编译器
您可以在 std::declval()的顶部添加以下内容:
#ifdef _MSC_VER
namespace std {
template <typename T>
typename add_rvalue_reference<T>::type declval();
}
#endif

关于c++ - 如何使用SFINAE检测类的存在?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10711952/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com