模板实例化混乱

Mr.*_*bis 7 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};
};
Run Code Online (Sandbox Code Playgroud)

如果我改变的第二个参数chtcheck(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
Run Code Online (Sandbox Code Playgroud)

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

wol*_*ang 3

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

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

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

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