slinae with decltype:clang或gcc中的bug?

Leo*_*sky 10 c++ gcc clang sfinae c++11

Clang-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); 
}
Run Code Online (Sandbox Code Playgroud)

任何版本的GCC拒绝:

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

谁是对的?Gcc还是Clang?

注意,有类似的问题,没有真正的答案.

eca*_*mur 9

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

1 - 使用通常的名称查找找到模板定义中使用的非依赖名称,并在使用它们时绑定.

给出的示例描述了模板定义中的错误表达" 可以[在模板定义中]或在实例化时被诊断 ".

默认的模板参数(14.1p9)U=decltype(t.f(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); }
Run Code Online (Sandbox Code Playgroud)

  • 可惜他们不像*默认参数*那样处理.因为默认参数像模板定义一样处理以进行实例化.因此,如果它是一个默认参数,那么只有在尝试使用函数模板时才会给出错误.但不幸的是,他所拥有的是一个默认的*template*参数. (2认同)