未能尝试编写智能转换模板功能
Failing in trying to code smart cast template function
我目前正在尝试根据 DRY 原则根据其输入和输出类型编写一个函数来执行 static_cast
或 dynamic_cast
。我要实现的功能如下:
#define where typename = typename
#define can_cast(FROM, TO) std::is_convertible<FROM, TO>::value
#define can_dynamic_cast(FROM, TO) \
can_cast(FROM, TO) && \
!std::is_same<FROM, TO>::value && \
std::is_class<TO>::value && \
!std::is_const<FROM>::value && \
std::is_base_of<TO, FROM>::value
#define can_static_cast(FROM, TO) can_cast(FROM, TO)
template<typename _Tout, typename _Tin, where
std::enable_if<
!std::is_pointer<_Tout>::value &&
!std::is_pointer<_Tin>::value &&
can_cast_ptr(_Tin, _Tout)>::type>
inline _Tout* gc_ptr_cast(_Tin* const p) {
if(can_dynamic_cast(_Tin*, _Tout*))
return dynamic_cast<_Tout*>(p);
if(can_dynamic_cast(_Tin*, _Tout*))
return static_cast<_Tout*>(p);
throw bad_cast();
}
但是由于编译器的抱怨,例如 gc_ptr_cast<int>(new int(1))
它不会工作:
[..] error: cannot dynamic_cast 'p' (of type 'int* const') to type 'int*' (target is not pointer or reference to class)
return dynamic_cast<_Tout*>(p)«;
编译器应该处理 static_cast
而不是 dynamic_cast
!
现在我什至不确定我是否在正确的路径中使用 <type_traits>
用于此目的。
我有半千个模板函数,其中一些我需要执行 static_cast
,其中一些我需要 dynamic_cast
,剩下的一半我需要执行检查两者。 dynamic_cast
在我的案例中很重要,因为它在下面的示例中是成功的,这是使事情正确的关键部分!
struct base1 {};
struct base2 {};
struct derived : public base1, public base2 {};
.
.
.
derived obj;
base1* p1 = &obj;
base2* p2 = &obj;
assert(dynamic_cast<void*>(p1) == dynamic_cast<void*>(p2)); // will succeed
assert(static_cast<void*>(p1) == static_cast<void*>(p2)); // will fail [ THIS IS WHY I CANNOT USE `static_cast` IN SOME CASES ]
我知道有一个 smart cast 的 boost 库,但我希望我的代码只依赖于 C++11 std。图书馆。
问题
1) 我做错了什么?
2) 我如何完成 gc_ptr_cast<>()
?
P.S: 可能我做的有些过头了,我已经输入了 can_dynamic_cast
但现在没问题了。
您正在尝试在运行时条件中使用编译时条件。这基本上是个坏主意。
inline _Tout* gc_ptr_cast(_Tin* const p) {
if(can_dynamic_cast(_Tin*, _Tout*))
return dynamic_cast<_Tout*>(p);
if(can_dynamic_cast(_Tin*, _Tout*))
return static_cast<_Tout*>(p);
throw bad_cast();
}
这应该根据编译时检查重写,因为 can_dynamic_cast
在您的情况下是编译时检查。
我认为这样的事情可以帮助你:
template<typename _Tout, typename _Tin>
inline _Tout* ptr_cast(_Tin* const p,
typename std::enable_if<can_dynamic_cast(_Tin*, _Tout*)>::type* = 0)
{
return dynamic_cast<_Tout*>(p);
}
template<typename _Tout, typename _Tin>
inline _Tout* ptr_cast(_Tin* const p,
typename std::enable_if<can_static_cast(_Tin*, _Tout*)>::type* = 0)
{
return static_cast<_Tout*>(p);
}
template<typename _Tout, typename _Tin>
inline _Tout* ptr_cast(_Tin* const p,
typename std::enable_if<!can_static_cast(_Tin*, _Tout*) &&
!can_dynamic_cast(_Tin*, _Tout*)>::type* = 0)
{
throw std::bad_cast();
}
template<typename _Tout, typename _Tin, where
std::enable_if<
!std::is_pointer<_Tout>::value &&
!std::is_pointer<_Tin>::value &&
can_cast(_Tin, _Tout)>::type>
inline _Tout* gc_ptr_cast(_Tin* const p) {
return ptr_cast<_Tout>(p);
}
我目前正在尝试根据 DRY 原则根据其输入和输出类型编写一个函数来执行 static_cast
或 dynamic_cast
。我要实现的功能如下:
#define where typename = typename
#define can_cast(FROM, TO) std::is_convertible<FROM, TO>::value
#define can_dynamic_cast(FROM, TO) \
can_cast(FROM, TO) && \
!std::is_same<FROM, TO>::value && \
std::is_class<TO>::value && \
!std::is_const<FROM>::value && \
std::is_base_of<TO, FROM>::value
#define can_static_cast(FROM, TO) can_cast(FROM, TO)
template<typename _Tout, typename _Tin, where
std::enable_if<
!std::is_pointer<_Tout>::value &&
!std::is_pointer<_Tin>::value &&
can_cast_ptr(_Tin, _Tout)>::type>
inline _Tout* gc_ptr_cast(_Tin* const p) {
if(can_dynamic_cast(_Tin*, _Tout*))
return dynamic_cast<_Tout*>(p);
if(can_dynamic_cast(_Tin*, _Tout*))
return static_cast<_Tout*>(p);
throw bad_cast();
}
但是由于编译器的抱怨,例如 gc_ptr_cast<int>(new int(1))
它不会工作:
[..] error: cannot dynamic_cast 'p' (of type 'int* const') to type 'int*' (target is not pointer or reference to class)
return dynamic_cast<_Tout*>(p)«;
编译器应该处理 static_cast
而不是 dynamic_cast
!
现在我什至不确定我是否在正确的路径中使用 <type_traits>
用于此目的。
我有半千个模板函数,其中一些我需要执行 static_cast
,其中一些我需要 dynamic_cast
,剩下的一半我需要执行检查两者。 dynamic_cast
在我的案例中很重要,因为它在下面的示例中是成功的,这是使事情正确的关键部分!
struct base1 {};
struct base2 {};
struct derived : public base1, public base2 {};
.
.
.
derived obj;
base1* p1 = &obj;
base2* p2 = &obj;
assert(dynamic_cast<void*>(p1) == dynamic_cast<void*>(p2)); // will succeed
assert(static_cast<void*>(p1) == static_cast<void*>(p2)); // will fail [ THIS IS WHY I CANNOT USE `static_cast` IN SOME CASES ]
我知道有一个 smart cast 的 boost 库,但我希望我的代码只依赖于 C++11 std。图书馆。
问题
1) 我做错了什么?
2) 我如何完成 gc_ptr_cast<>()
?
P.S: 可能我做的有些过头了,我已经输入了 can_dynamic_cast
但现在没问题了。
您正在尝试在运行时条件中使用编译时条件。这基本上是个坏主意。
inline _Tout* gc_ptr_cast(_Tin* const p) {
if(can_dynamic_cast(_Tin*, _Tout*))
return dynamic_cast<_Tout*>(p);
if(can_dynamic_cast(_Tin*, _Tout*))
return static_cast<_Tout*>(p);
throw bad_cast();
}
这应该根据编译时检查重写,因为 can_dynamic_cast
在您的情况下是编译时检查。
我认为这样的事情可以帮助你:
template<typename _Tout, typename _Tin>
inline _Tout* ptr_cast(_Tin* const p,
typename std::enable_if<can_dynamic_cast(_Tin*, _Tout*)>::type* = 0)
{
return dynamic_cast<_Tout*>(p);
}
template<typename _Tout, typename _Tin>
inline _Tout* ptr_cast(_Tin* const p,
typename std::enable_if<can_static_cast(_Tin*, _Tout*)>::type* = 0)
{
return static_cast<_Tout*>(p);
}
template<typename _Tout, typename _Tin>
inline _Tout* ptr_cast(_Tin* const p,
typename std::enable_if<!can_static_cast(_Tin*, _Tout*) &&
!can_dynamic_cast(_Tin*, _Tout*)>::type* = 0)
{
throw std::bad_cast();
}
template<typename _Tout, typename _Tin, where
std::enable_if<
!std::is_pointer<_Tout>::value &&
!std::is_pointer<_Tin>::value &&
can_cast(_Tin, _Tout)>::type>
inline _Tout* gc_ptr_cast(_Tin* const p) {
return ptr_cast<_Tout>(p);
}