-
12-09-2019 - |
题
我们有一个子项目'commonUtils',具有许多的通用代码段使用跨父项目。一个这样的有趣的东西我看到的是:-
/*********************************************************************
If T is polymorphic, the compiler is required to evaluate the typeid
stuff at runtime, and answer will be true. If T is non-polymorphic,
the compiler is required to evaluate the typeid stuff at compile time,
whence answer will remain false
*********************************************************************/
template <class T>
bool isPolymorphic() {
bool answer=false;
typeid(answer=true,T());
return answer;
}
我相信评论,并认为这是一个相当有趣的模板,但它不是 用于整个项目。我尝试使用这样的只是好奇...
class PolyBase {
public:
virtual ~PolyBase(){}
};
class NPolyBase {
public:
~NPolyBase(){}
};
if (isPolymorphic<PolyBase>())
std::cout<<"PolyBase = Polymorphic\n";
if (isPolymorphic<NPolyBase>())
std::cout<<"NPolyBase = Also Polymorphic\n";
但没有那些曾经返回正确的。MSVC2005年没有给出警告,但科莫警告typeid表达没有任何影响。部分5.2.8在C++标准不会说什么,喜欢什么样的评论说:即typeid是评估在编译的时间不多态的类型和运行为的多晶型类型。
1)因此,我想评论具有误导性/纯的错误或因为提交人的这种代码是一个相当高C++编程,我失去了一些东西?
2)另一方面,我想知道如果我们可以测试是否类是多态性(至少有一个虚拟的功能)使用一些技术?
3)如果一个人想要知道,如果一类是多态?猜猜;为获得启动地址的一类通过使用 dynamic_cast<void*>(T)
(作为 dynamic_cast
仅适用于多晶型类)。
在等待你的意见。
在此先感谢,
解决方案
我无法想象任何可能的方式如何那typeid的可以用来检查类型是多态的。它甚至不能用来断言它是,因为typeid运算可以在任何类型的工作。 升压这里有一个实现。至于为什么它可能是必要的 - 一个情况下,我知道的是Boost.Serialization库。如果要保存非多态类型,那么你可以将它保存。如果在保存多态之一,你必须使用的typeid以获取其动态类型,然后调用该类型的序列化方法(在某些表了寻找它)。
更新:看来我其实是错误的。考虑该变体:
template <class T>
bool isPolymorphic() {
bool answer=false;
T *t = new T();
typeid(answer=true,*t);
delete t;
return answer;
}
这实际上确实工作作为顾名思义,正是根据注释在原始代码段。内部typeid的表达,如果它“不指定多态类类型的左值”(STD 3.2 / 2)不进行评价。因此,在上述情况下,如果T是不是多态的,所述typeid的表达不进行评价。如果T是多态的,那么* t是确实左值多态型的,所以整个表达式必须被评估。
现在,你原来的例子仍然是错误的:-)。它使用T()
,不*t
。和T()
创建的右值强>(STD 3.10 / 6)。因此,它仍产生不“多态类的左值”。
这是相当有趣的把戏。在另一方面,它的实用价值是比较有限的 - 因为虽然升压:: is_polymorphic给你一个编译时间常数,这个人给你一个运行时间值,所以你不能实例化多态和非多态类型不同的代码
其他提示
class PolyBase {
public:
virtual ~PolyBase(){}
};
class NPolyBase {
public:
~NPolyBase(){}
};
template<class T>
struct IsPolymorphic
{
struct Derived : T {
virtual ~Derived();
};
enum { value = sizeof(Derived)==sizeof(T) };
};
void ff()
{
std::cout << IsPolymorphic<PolyBase >::value << std::endl;
std::cout << IsPolymorphic<NPolyBase>::value << std::endl;
}
由于C ++ 11,这是目前在<type_traits>
标头,如std::is_polymorphic
可用。它可用于这样的:
struct PolyBase {
virtual ~PolyBase() {}
};
struct NPolyBase {
~NPolyBase() {}
};
if (std::is_polymorphic<PolyBase>::value)
std::cout << "PolyBase = Polymorphic\n";
if (std::is_polymorphic<NPolyBase>::value)
std::cout << "NPolyBase = Also Polymorphic\n";
此打印只是 “多碱=多态性”。
一个可以使用的事实是:
dynamic_cast
失败在编制时间,如果说法不是一个多晶型类。因此,它可以被用于与SFINAE.dynamic_cast<void*>
是一个有效的投返回的地址 完整的 polymorpic对象。
因此,在C++11:
#include <iostream>
#include <type_traits>
template<class T>
auto is_polymorphic2_test(T* p) -> decltype(dynamic_cast<void*>(p), std::true_type{});
template<class T>
auto is_polymorphic2_test(...) -> std::false_type;
template<class T>
using is_polymorphic2 = decltype(is_polymorphic2_test<T>(static_cast<T*>(0)));
struct A {};
struct B { virtual ~B(); };
int main() {
std::cout << is_polymorphic2<A>::value << '\n'; // Outputs 0.
std::cout << is_polymorphic2<B>::value << '\n'; // Outputs 1.
}
我有点糊涂了这里,并且我希望能得到这样的回答一些意见解释,我错过了什么。
当然,如果你想找出一类是多态的,所有你需要做的就是询问是否支持dynamic_cast
,是不是啊?
template<class T, class> struct is_polymorphic_impl : false_type {};
template<class T> struct is_polymorphic_impl
<T, decltype(dynamic_cast<void*>(declval<T*>()))> : true_type {};
template<class T> struct is_polymorphic :
is_polymorphic_impl<remove_cv_t<T>, void*> {};
任何人都可以指出在此实现的一个漏洞?我想必须有一个,或者一定是一个在过去的某个时间,因为的升压文档继续声称is_polymorphic
‘不能在C ++语言来实现可移植’。
但是,“便携”是怎样的一个黄鼠狼字的,对不对?也许他们只是暗指MSVC怎么不支持表达式SFINAE,或者一些方言,如嵌入式C ++不支持dynamic_cast
。也许当他们说:“C ++语言”,他们说“一个C ++语言的最小公分母的子集。”但我有一种挥之不去的怀疑,也许他们的意思,他们说什么,我的一个谁失去了一些东西。
在OP的typeid
办法(修订通过后的答案用一个左不右值)也似乎很好,但当然这不是constexpr,它需要真正构建T
de,这可能是超贵。所以这dynamic_cast
做法似乎更好......除非它不适用于某些原因。想法?