我有一个指针类的子集,如下所示:
template <typename T>
struct Pointer
{
Pointer();
Pointer(T *const x);
Pointer(const Pointer &x);
template <typename t>
Pointer(const Pointer<t> &x);
operator T *() const;
};
最后一个构造函数的目标是允许传递 Pointer
子类的,或者基本上任何可以隐式转换为 T *
的类型.这个实际规则仅由构造函数的定义强制执行,编译器实际上无法仅通过声明来计算它。如果我放弃它,并尝试传递 Pointer<Sub>
到 Pointer<Base>
的构造函数,我得到一个编译错误,尽管可能通过 operator T *()
的路径.
虽然它解决了上述问题,但它又产生了另一个问题。如果我有一个重载函数,它的一个重载需要一个 Pointer<UnrelatedClass>
另一个需要Pointer<BaseClass>
,我尝试用 Pointer<SubClass>
调用它,我在两个重载之间有歧义,当然,意图是调用后一个重载。
有什么建议吗? (希望我足够清楚)
最佳答案
解决您的问题的方法称为 SFINAE(替换失败不是错误)
#include "boost/type_traits/is_convertible.hpp"
#include "boost/utility/enable_if.hpp"
template<typename T>
class Pointer {
...
template<typename U>
Pointer(const Pointer<U> &x,
typename boost::enable_if<
boost::is_convertible<U*,T*>
>::type* =0)
: ...
{
...
}
...
};
如果 U* 可转换为 T* enable_if
将有一个 typedef 成员 type
默认为 void。然后,一切都很好。如果 U* 不可转换为 T*,则缺少此 typedef 成员,替换失败并忽略构造函数模板。
这解决了您的转换和歧义问题。
回应评论:is_convertible
看起来像这样:
typedef char one; // sizeof == 1 per definition
struct two {char c[2];}; // sizeof != 1
template<typename T, typename U>
class is_convertible {
static T source();
static one sink(U);
static two sink(...);
public:
static const bool value = sizeof(sink(source()))==1;
};
关于C++模板和歧义问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1897844/