我有一个指针类的子集,如下所示:
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>
调用它,我在两个重载之间得到一个模糊性,当然,意图是后者超载将被称为。
有什么建议吗? (希望我很清楚)
答案 0 :(得分:6)
解决问题的方法称为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
默认为无效。然后,一切都很好。如果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;
};
答案 1 :(得分:0)
尝试使有问题的构造函数明确,例如:
template <typename t>
explicit Pointer(const Pointer<t> &x);
和/或删除operator T *() const;
- 我认为这也会造成歧义。
修改强>
检查std::auto_ptr界面,并与您的界面进行比较。至少他们解决了歧义。