在尝试回答this question时,我想建议使用enable_if
+ disable_if
来允许基于类型是(或不是)多态的事实重载
所以我创建了一个小测试文件:
template <class T>
void* address_of(T* p,
boost::enable_if< boost::is_polymorphic<T> >* dummy = 0)
{ return dynamic_cast<void*>(p); }
template <class T>
void* address_of(T* p,
boost::disable_if< boost::is_polymorphic<T> >* dummy = 0)
{ return static_cast<void*>(p); }
struct N { int x; };
int main(int argc, char* argv[])
{
N n;
std::cout << address_of(&n) << std::endl;
return 0;
}
看起来很温顺。
然而gcc(3.4 ......)对此嗤之以鼻:
test.cpp:在函数
int main(int, char**)
中:
test.cpp:29:错误:重载address_of(N*)
的调用是模糊的 test.cpp:17:注意:候选人是:void* address_of(T*, boost::enable_if<boost::is_polymorphic<T>, void>*)
[有T = N]
test.cpp:20:注意:void* address_of(T*, boost::disable_if<boost::is_polymorphic<T>, void>*)
[有T = N]
我的人类思维似乎很清楚这里应该使用过载。我的意思是很明显我已经定义了一个替代方案,并且一次只能使用一个函数......而且我会认为SFINAE会照顾无效的过载。
我使用...
(省略号)而不是disable_if
来修补它,并且需要一个虚拟的第二个参数...但我仍然对编译器为什么会对此产生阻塞感兴趣。
答案 0 :(得分:11)
编译器因为忘记::type
和enable_if
上的disable_if
结尾而被阻塞。始终定义模板;当且仅当表达式为type
(对于true
)或enable_if
(对于false
)时,成员disable_if
才会出现。
template <class T>
void* address_of(T* p,
typename boost::enable_if< boost::is_polymorphic<T> >::type* dummy = 0)
{ return dynamic_cast<void*>(p); }
template <class T>
void* address_of(T* p,
typename boost::disable_if< boost::is_polymorphic<T> >::type* dummy = 0)
{ return static_cast<void*>(p); }
如果没有尾随::type
,您的函数模板只会创建重载,指针指向enable_if
或disable_if
的实例作为第二个参数。使用尾随::type
,模板要么创建带有第void*
类型的第二个参数的重载,要么删除重载(即所需的行为)。
答案 1 :(得分:0)
使用“返回类型”版本的enable_if在3.4.4中起作用:gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_polymorphic.hpp>
#include <iostream>
template <class T>
typename boost::enable_if< boost::is_polymorphic<T>, void* >::type
address_of(T* p)
{ return dynamic_cast<void*>(p); }
template <class T>
typename boost::disable_if< boost::is_polymorphic<T>, void* >::type
address_of(T* p)
{ return static_cast<void*>(p); }
struct N { int x; };
int main(int argc, char* argv[])
{
N n;
std::cout << address_of(&n) << std::endl;
return 0;
}