changsheng
changsheng

Reputation: 101

g++ fails to look up static functions in a template class, is it a bug or standard defined?

When I try some C++11 code like following, it passed in all clang++ available to me that support C++11, but it failed to compile in g++-4.8, g++-4.9 and g++-5.0.

#include <type_traits>
#include <vector>

template <class C, class First, class Last>
struct HasInsertEnd {
  template <class U>
  static std::false_type Check(...);

  template <class U>
  static auto Check(U val)
      -> decltype(val.insert(val.end(), std::declval<First>(),
                             std::declval<Last>()),
                  std::true_type{});

  template <class U>
  using Deduce = decltype(Check<U>(std::declval<U>()));

  using type = typename Deduce<C>::type;
  static constexpr bool value = type::value;
};

int main(int argc, char* argv[]) {
  static_assert(!HasInsertEnd<int, int, int>::value, "...");
  static_assert(HasInsertEnd<std::vector<int>, const int*, const int*>::value,
                "...");
  return 0;
}

g++ will report errors like:

‘Check’ was not declared in this scope

If I change the calling of Check in the Deduce to HasInsertEnd::Check, both g++ and clang++ will be happy.

I know little about dependent name lookup. The problem is, which behavior is standard?

Upvotes: 3

Views: 164

Answers (1)

user743382
user743382

Reputation:

This is a bug in GCC, and can be shown to be a bug in GCC even without deferring to the standard.

template <typename T>
struct f { typedef int type; };

template <typename T>
struct S {
  template <typename U>
  static f<U> f();

  template <class U>
  using u = typename decltype(f<U>())::type;

  using t = u<T>;
};

S<int>::t main() { }

This is rejected the same way in GCC 4.7.4 and GCC 5, with "error: ‘f’ was not declared in this scope". That's just nonsense. Even if the static member function should somehow not be visible, there is still a global type by the same name that would be found instead. It gets even better, though: with that global type, you get:

test.cc: In substitution of ‘template<class T> template<class U> using u = typename decltype (f<U>())::type [with U = T; T = T]’:
test.cc:12:20:   required from here
test.cc:10:36: error: ‘f’ was not declared in this scope
       using u = typename decltype(f<U>())::type;
                                    ^
test.cc:10:36: note: suggested alternative:
test.cc:2:12: note:   ‘f’
     struct f { typedef int type; };
            ^
test.cc:15:13: error: ‘t’ in ‘struct S<int>’ does not name a type
     S<int>::t main() { }
             ^

That's right, it's suggesting that f can be corrected by spelling it f.

I don't see any problem with your code, and if it isn't a known bug, I encourage you to report it. and it's been reported as a bug before.

Oddly, as noted in the comments, GCC 4.8.4 and GCC 4.9.2 do find a global f. However, if the global f is a type, then they still reject the program, with "error: missing template arguments" even though the template argument is provided, so it's still clearly a bug in GCC.

Upvotes: 3

Related Questions