Mik*_*han 36
如果我们要求编译器告诉我们关于T
甚至没有声明的类类型的任何信息,我们必然会遇到编译错误.没有办法绕过那个.因此,如果我们想知道类是否T
"存在",T
甚至可能尚未宣布,我们必须先声明T
.
但是,这是确定的,因为仅仅是宣布T
将不会使其"存在",因为我们必须意味着T
存在是T
被定义.如果,在声明之后T
,您可以确定它是否已经定义,您不必担心任何混乱.
所以问题是确定T是否是定义的类类型.
T
这里没有帮助.如果sizeof(T)
未定义则会
T
出错.同样地incomplete type T
.这也不是什么好各具特色的类型的SFINAE探头typeid(T)
,因为T *
是在定义的类型,只要T *
已经宣布,即使T
是没有的.既然我们有义务宣布上课T
,T
也不是答案,因为这个声明足以让它说"是".
C++ 11提供std::is_class<T>
在std::is_constructible<T ...Args>
.这可以提供一个现成的解决方案吗?- 假定if <type_traits>
已定义,那么它必须至少有一个构造函数.
我不高兴.如果您知道T
当时GCC T
(截至4.6.3)的至少一个公共构造函数的签名确实会开展业务.假设一个已知的公共构造函数是<type_traits>
.然后:
std::is_constructible<T,int>::value
Run Code Online (Sandbox Code Playgroud)
如果T::T(int)
定义则为true,如果T
仅声明则为false .
但这不便携.T
在VC++ 2010中还没有提供
<type_traits>
甚至它的std::is_constructible
意志如果std::has_trivial_constructor<T>
没有定义:最有可能何时T
到达它将跟随.此外,在可能的情况下,只有私人建设者std::is_constructible
提供给T
当时甚至GCC将barf(这是眉毛提高).
如果std::is_constructible
已定义,则必须具有析构函数,并且只有一个析构函数.而且,这个析构函数比任何其他可能的成员更有可能公开T
.从这个角度来看,我们可以做的最简单和最强大的游戏是制作一个SFINAE探测器来存在T
.
此SFINAE探针无法以常规方式制作,以确定是否T::~T
具有普通成员函数T
- 使SFINAE探测函数的"是重载"采用根据类型mf
定义的参数.因为我们不允许使用析构函数(或构造函数)的地址.
然而,如果&T::mf
被定义,则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
Run Code Online (Sandbox Code Playgroud)
只有DT *
必须在参数表达式中合法调用公共析构函数的限制T
.(这decltype(std::declval<A>().~A())
是我在这里贡献的方法 - 内省模板的简化改编.)
具体而言,该参数表达式的含义has_destructor<T>
可能对某些人来说是模糊的std::declval<A>().~A()
.函数模板
std::declval<A>()
定义在std::declval<T>()
并返回
<type_traits>
(rvalue-reference to T&&
) - 尽管它只能在未评估的上下文中调用,例如参数T
.所以意思
decltype
是呼唤std::declval<A>().~A()
某些给定的~A()
.
A
通过避免需要任何公共建设者std::declval<A>()
或我们了解它来为我们提供良好的服务.
因此,"Yes overload"的SFINAE探测器的参数类型是:
指向析构函数类型的指针T
,并且A
只有在存在类型为析构函数的test<T>(0)
情况下才匹配该重载,for 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;
}
Run Code Online (Sandbox Code Playgroud)
使用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
Run Code Online (Sandbox Code Playgroud)
Win*_*lds 14
仍然没有在这篇文章中找到令人满意的答案......
迈克金汉开始正确的答案并告诉一个聪明的事情:
所以问题是确定T是否是定义的类类型.
但
sizeof(T)在这里没有帮助
是不正确的...
以下是如何使用以下方法sizeof(T)
:
template <class T, class Enable = void>
struct is_defined
{
static constexpr bool value = false;
};
template <class T>
struct is_defined<T, std::enable_if_t<(sizeof(T) > 0)>>
{
static constexpr bool value = true;
};
Run Code Online (Sandbox Code Playgroud)
有了SFINAE,没有.我认为名称查找技巧是完成这项工作的方法.如果您不害怕在库的命名空间中注入名称:
namespace lib {
#if DEFINE_A
class A;
#endif
}
namespace {
struct local_tag;
using A = local_tag;
}
namespace lib {
template <typename T = void>
A is_a_defined();
}
constexpr bool A_is_defined =
!std::is_same<local_tag, decltype(lib::is_a_defined())>::value;
Run Code Online (Sandbox Code Playgroud)
如果A
在全局命名空间中声明:
#if DEFINE_A
class A;
#endif
namespace {
struct local_tag;
using A = local_tag;
}
namespace foo {
template <typename T = void>
::A is_a_defined();
}
constexpr bool A_is_defined =
!std::is_same<local_tag, decltype(foo::is_a_defined())>::value;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
7935 次 |
最近记录: |