2009-12-13 103 views
3

我有一个指针类的子集,它看起来像:C++模板和模糊问题

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

这是更为常见的使用大写字母'U'额外的模板参数。小写't'几乎看起来像一个错字。 – GManNickG 2009-12-13 21:43:57

+0

隐式转换是一个坏主意。使用'T * get()'而不是'运算符T *()'。 shared_ptr做这样的事情。 – 2009-12-13 21:49:38

回答

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; 
}; 
+0

明白了,好主意。该项目暂时不使用提升。任何想法如何'is_convertible'的作品? – cvb 2009-12-13 22:00:46

+0

是的。随时upvote。:) – sellibitze 2009-12-13 22:10:56

+0

会upvoted十倍,但我没有注册:) – cvb 2009-12-13 22:23:18

0

尽量让有问题明确的构造函数,例如:

template <typename t> 
explicit Pointer(const Pointer<t> &x); 

和/或删除operator T *() const; - 我想,这其中也将产生歧义。

编辑

检查std::auto_ptr接口,并与你进行比较。至少他们解决了歧义。

+0

将'explicilt'添加到声明中会产生相同的效果:它会生成一个编译错误(2个重载都不能转换所有参数类型...)。移除铸造操作符并不能解决amibguity问题(无论如何,它是这个类的宝贵部分)。 – cvb 2009-12-13 21:49:09

+0

您可以添加代码,使用指针,请添加(作为注释)出现编译错误的位置,以及哪个错误。 – Frunsi 2009-12-13 21:58:11

+0

虽然铸造操作员仍然可能是造成这种困境的原因(正如Alexey指出的那样) ,隐式转换是一个糟糕的主意:std :: auto_ptr没有添加它,并且boost ptrs不会因为相同的原因添加它(在某些情况下是ambuigity)。 – Frunsi 2009-12-13 22:00:52