Clang's behavior is correct. This is a GCC bug (and the claim in the presentation is also incorrect). §3.3.2 [basic.scope.pdecl]/p1,6:
1 The point of declaration for a name is immediately after its
complete declarator (Clause 8) and before its initializer (if any),
except as noted below.
6 After the point of declaration of a class member, the member name can
be looked up in the scope of its class.
And §3.3.7 [basic.scope.class]/p1 says
The following rules describe the scope of names declared in classes.
1) The potential scope of a name declared in a class consists not only
of the declarative region following the name’s point of declaration,
but also of all function bodies, default arguments,
exception-specifications, and brace-or-equal-initializers of
non-static data members in that class (including such things in nested
classes).
trailing-return-types are not in that list.
The trailing return type is part of the declarator (§8 [dcl.decl]/p4):
declarator:
ptr-declarator
noptr-declarator parameters-and-qualifiers trailing-return-type
and so the variadic version of sum
isn't in scope within its own trailing-return-type and cannot be found by name lookup.
In C++14, simply use actual return type deduction (and omit the trailing return type). In C++11, you may use a class template instead and a function template that simply forwards:
template<class T, class... Args>
struct Sum {
static auto sum(T n, Args... rest) -> decltype(n + Sum<Args...>::sum(rest...)) {
return n + Sum<Args...>::sum(rest...);
}
};
template<class T>
struct Sum<T>{
static T sum(T n) { return n; }
};
template<class T, class... Args>
auto sum(T n, Args... rest) -> decltype(Sum<T, Args...>::sum(n, rest...)){
return Sum<T, Args...>::sum(n, rest...);
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…