7

这是我检查类是否具有成员函数的代码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};
};

如果我将chtin的第二个参数更改check(cht< Iter (fallBack::*)() const, &C::begin>*);&checker::begin,这不会改变代码的语义,因为cht的第二个模板参数总是checker由于这个enum {no = (sizeof(check<checker>(0))==sizeof(char))

但是代码更改现在会导致错误:

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

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

4

1 回答 1

3

来自关于 SFINAE 的 Wikipedia 文章 - 替换失败不是错误:

[...] 在为重载决议创建候选集时,该集的一些(或全部)候选集可能是用推导的模板参数替换模板参数的结果。如果在替换过程中发生错误,编译器会从候选集中移除潜在的重载,而不是因为编译错误而停止 [...]

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

如果您更改代码,则会出现类似的歧义错误&checker::begin。然而这一次,并不是用模板参数 C 代替check函数模板的结果。模板参数 T ofstruct has_begin的替换与 SFINAE 规则无关,因为该模板已经成功实例化。

于 2011-12-15T10:46:53.817 回答