与decltype SFINAE:错误的铛或GCC?(sfinae with decltype: b

2019-08-01 07:18发布

锵-3.2可以编译和代码像预期的那样:

struct have_f { int f(int i) {return 10;} }; 

struct empty {};

template <class T> 
struct outer {
        T t; 

        // if T have f(), define  outer_f()
        template<class U=decltype(t.f(1))> 
        int outer_f(int i) { return t.f(i); }
};

int main() {
        outer<have_f>  o1;
        outer<empty>   o2;

        // to silence unused var warning
        return  o1.outer_f(10) + sizeof(o2); 
}

任何版本的GCC拒绝使用:

t.cc:13:6: error: ‘struct empty’ has no member named ‘f’
  int outer_f(int i) { return t.f(i); }
      ^

谁是正确的? GCC或铛?

注意,出现了类似的问题 ,没有真正的答案。

Answer 1:

我相信这个问题是14.6.3 [temp.nondep]:

1 - 模版定义使用的非依赖性名称使用常用的名称查找发现和使用它们的点约束。

给出的实施例描述了模板定义内的形成不良的表述“ 可以被任一[在模板定义]或在实例化的点诊断 ”。

默认模板参数 (14.1p9) U=decltype(tf(1))是的实例化的上下文中的非从属名称struct outer (即,它不依赖于模板参数到它自己的模板)因此它是形成不良的供的实例化struct outerT = struct empty 。 该标准并没有明确说明,其中默认模板参数进行评估,但唯一明智的结论是,他们被视为任何其他结构和评估在它们发生的点(或者,在这个例子中,在实例化点struct outer模板)。 我没有看到任何纬度编译器延迟的非相关的默认模板参数评测到SFINAE应用环境。

幸运的是,解决方案很简单:只需使默认模板参数U一个从属名称:

    // if T have f(), define  outer_f()
    template<class T2 = T, class U=decltype(static_cast<T2 &>(t).f(1))> 
    int outer_f(int i) { return t.f(i); }


文章来源: sfinae with decltype: bug in clang or gcc?