cvb*_*cvb 3 c++ templates ambiguity implicit-cast ambiguous-call
我有一个指针类的子集,如下所示:
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;
};
Run Code Online (Sandbox Code Playgroud)
最后一个构造函数的目标是允许传递Pointer一个子类,或者基本上可以隐式转换为的任何类型T *.这个实际规则只能由构造函数的定义强制执行,而编译器实际上无法通过声明单独解决它.如果我删除它,并尝试传递Pointer<Sub>给构造函数Pointer<Base>,我会得到一个编译错误,尽管可能的路径通过operator T *().
虽然它解决了上述问题,但却创造了另一个问题.如果我有一个重载函数,其中一个重载占用a Pointer<UnrelatedClass>而另一个占用Pointer<BaseClass>,并且我尝试用a调用它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)
: ...
{
...
}
...
};
Run Code Online (Sandbox Code Playgroud)
如果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;
};
Run Code Online (Sandbox Code Playgroud)