简体   繁体   中英

error determining a generic return type in C++11

In the context of a C++14 application, I use a scheme which could be resumed as follows (minimal reproducible test):

template <class Container>
struct LocateFunctions {    
  auto get_it() const // <-- here is the problem
  {
    auto ret = typename Container::Iterator();
    return ret;
  }
};

template <typename T>
struct A : public LocateFunctions<A<T>> {    
  struct Iterator {};
};

int main() {  
  A<int> a;
}

This approach compiles and runs perfectly in C++14, with GCC and Clang compilers.

Now I want migrate my application to Windows and for that I'm using MinGW. Unfortunately, its latest version brings GCC 4.9 which does not compile C++14. That does not seem like a serious problem because I can rewrite the C++14 constructs in C++11. So, I rewrite the get_it() method as follows:

typename Container::Iterator get_it() const
{ 
  auto ret = typename Container::Iterator();
  return ret;
}

Unfortunately it does no compile. Both compilers produce the following error:

error: no type named ‘Iterator’ in ‘struct A<int>’
   typename Container::Iterator get_it() const
                            ^

I also tried:

auto get_it() const -> decltype(typename Container::Iterator())
{ 
  auto ret = typename Container::Iterator();
  return ret;
}

but I get exactly the same error.

Since two compilers fail to recognize the type of return, I suppose it is impossible to determine it. But I do not really know why.

Could someone please explain me why not compile and eventually a way for refactoring in C++11 that compiles?

You're using CRTP; LocateFunctions is instantiated with an incomplete specialization of A ( A<int> ), hence accessing that specialization's members gives the rather misleading error message ("no … named … in …" instead of "… is incomplete"). However, in your example the function temploid get_it is only (if ever) instantiated after A<int> is indeed defined , making the typename-specifier well-formed.

As for a workaround, try to achieve a similar effect, eg via

template <typename T=Container>
typename T::Iterator get_it() const
{
    static_assert(std::is_same<T, Container>{}, "You ain't supposed to supply T!");
    auto ret = typename T::Iterator();
    return ret;
}

Demo with GCC 4.9.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM