检查类型被定义
考虑这个例子:检查类型被定义
#include <iostream>
#include <type_traits>
template <class, class = void>
struct is_defined : std::false_type
{ };
template <class T>
struct is_defined<T,
std::enable_if_t<std::is_object<T>::value &&
!std::is_pointer<T>::value
>
> : std::true_type
{
private:
static const T test; //try to create incomplete type member
};
struct defined { };
struct forward_declared;
int main()
{
std::cout << std::boolalpha
<< is_defined<defined>::value << std::endl
<< is_defined<forward_declared>::value << std::endl;
}
输出是true
两者。我想如果我尝试使不完整类型的成员struct
成员,那么这个模板专门化将从超载设置中丢弃。但事实并非如此。删除static const
会导致不完整的编译时错误。这种方法有什么问题,如果可能的话,怎么能实现呢?
试试这个:
template <class T>
struct is_defined<T,
std::enable_if_t<std::is_object<T>::value &&
!std::is_pointer<T>::value &&
(sizeof(T) > 0)
>
> : std::true_type
{
};
哇,这是快速的:)你能解释为什么我们可以通过尝试在不完整类型上应用'sizeof'来放弃超载,但是我们不能通过使'T'成员来做到这一点? – xinaiz
@BlackMoses这只是你的普通的SFINAE。 'sizeof'不适用于不完整的类型,所以替换将失败。 –
关于问题“什么是不对的做法......” 当我们有静态常量T检验;它不是is_defined < ...>类的一部分,我们实际上必须定义静态成员is_defined < ...> ::测试别的地方,只有在那个“其他”地方,我们需要T是完整类型。 is_defined < ...>仅仅因为静态成员大小对is_defined < ...>大小没有影响才编译类。
去除静态const会导致T test;成为is_defined < ...>(并且影响is_defined < ...> size)的成员,因此T必须是完整类型才能具有已知大小。
UPD注:在声明类构件在模板特它不是由SFINAE丢弃仅仅因为这是也不是“参数替换”,也不是一种“SFINAE表达”的情况下(以及不是函数超载!)。相反,它是某种“SFINAE现场声明” - 而不是标准中所述的“替代失败时不是错误”。
感谢您的解释。但是,当这种不完整类型是成员时,为什么模板专门化不会从过载中丢弃?相反,它会导致错误。 – xinaiz
在模板特化中声明类成员的情况下,它不会被SFINAE丢弃,因为这不是“参数替换”,也不是“SFINAE表达式”(也不是被重载的函数!)。相反,它是某种“SFINAE现场声明” - 而不是标准中所述的“替代失败时不是错误”。 –
一般来说,在这种情况下,您可以使用您的sfinae表达式中的某些不接受不完整类型的运算符。
举个例子,你可以使用typeid
:
#include <iostream>
#include <type_traits>
#include <utility>
template<typename T, typename = void>
constexpr bool is_defined = false;
template<typename T>
constexpr bool is_defined<T, decltype(typeid(T), void())> = true;
struct defined { };
struct forward_declared;
int main()
{
std::cout << std::boolalpha
<< is_defined<defined> << std::endl
<< is_defined<forward_declared> << std::endl;
}
正如其他人所提到的,另一个有效运营商sizeof
。
'is_object'并不意味着'is_complete'。 –
@ n.m。这只是为了不允许检查参考。我可以使用'std :: is_reference'来代替,但这并没有太大的不同。 – xinaiz
好的我看到你正在试图声明一个静态的东西去除不完整的类型。无论如何,你需要使用ODR来使用静态的东西。 –