模板实例化混乱

时间:2011-12-15 10:07:53

标签: c++ templates sfinae

这是我的代码,用于检查类是否具有成员函数begin

template<typename T> struct has_begin
{
    struct dummy {typedef void const_iterator;};
    typedef typename std::conditional< has_iterator<T>::yes, T, dummy>::type TType;
    typedef typename TType::const_iterator Iter;
    struct fallBack{ Iter begin() const ; Iter end() const;};
    struct checker : T, fallBack {};
    template <typename B, B> struct cht;
    template<typename C> static char check(cht< Iter (fallBack::*)() const, &C::begin>*); // problem is here
    template<typename C> static char (&check(...))[2];
public:
    enum {no = (sizeof(check<checker>(0))==sizeof(char)),
     yes=!no};
};

如果我将chtcheck(cht< Iter (fallBack::*)() const, &C::begin>*);的第二个参数更改为 &checker::begin,由于此cht

checker的第二个模板参数始终为enum {no = (sizeof(check<checker>(0))==sizeof(char)),因此不会更改代码的语义

但代码更改现在导致error

prog.cpp: In instantiation of 'has_begin<std::vector<int> >':
prog.cpp:31:51:   instantiated from here
prog.cpp:23:38: error: reference to 'has_begin<std::vector<int> >::checker::begin' is ambiguous

我想知道这种行为背后的原因是什么。

1 个答案:

答案 0 :(得分:3)

来自维基百科关于SFINAE的文章 - 替换失败不是错误:

  

[...]在为重载决策创建候选集时,有些(或全部)   该集合的候选人可能是取代推断的结果   模板参数的模板参数。如果发生错误   在替换期间,编译器从中删除潜在的重载   候选集而不是停止编译错误[...]

在发布的代码中,在使用参数check == C实例化函数模板typename has_begin<T>::checker时出现歧义错误,并且该替换会导致错误,因此实例化是只需从过载集中删除。

如果您更改了代码,则&checker::begin会出现类似的模糊错误。 但是,这次不是将模板参数C替换为check函数模板的结果。 struct has_begin的模板参数T的替换与SFINAE规则无关,因为该模板已成功实例化。