3

The code below gives the error error C2039: 'value_type': is not a member of 'Child_Container' on line 7. This happens in MSVC and Clang, but not with GCC. Thereby when using std::deque, but not std::set, std::vector. Does anyone know why? Thank you!

#include <deque>

template<typename T_Container>
struct _View
{
    using           NOPE = typename T_Container::value_type;
};

template<typename T_type, typename T_Self>
struct Base_Container
{
    using value_type = T_type;
    std::deque<_View<T_Self>>   _views;
};

struct Child_Container : public Base_Container<double, Child_Container>
{
    // using value_type = double; // Even with this line.
    using base = Base_Container<value_type, Child_Container>;
};

int main()
{
    return 0;
}
JMRC
  • 1,473
  • 1
  • 17
  • 36
  • 1
    Probably unrelated, but careful with how you use underscores. An underscore followed by a capital letter is reserved for use by The Implementation. See [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – user4581301 Jun 01 '21 at 04:56
  • @user4581301 Thanks for the tip. It is actually in a namespace. – JMRC Jun 01 '21 at 04:58
  • 1
    @JMRC, Whether it's in a namespace is irrelevant; said names are reserved in any context (i.e., an implementation could name a macro that or use it as a compiler builtin). – chris Jun 01 '21 at 05:00
  • @user4581301 Ahh. Didn't think about that. – JMRC Jun 01 '21 at 05:02
  • 2
    This appears to be library-specific rather than compiler-specific. Clang compiles this with libstdc++, but not with libc++. – chris Jun 01 '21 at 05:07
  • @chris I noticed that as well. There must be some difference in container templates. https://godbolt.org/z/ThzfKEhTh – Maciej Załucki Jun 01 '21 at 05:11
  • Unsurprisingly, using a `self_t` directly instead of indirecting it through CRTP works fine: https://godbolt.org/z/3eaj4756a –  Jun 01 '21 at 05:32
  • 1
    Note the only `std` container class templates you're allowed to instantiate with an incomplete type as the first template argument are `std::vector`, `std::list`, and `std::forward_list`. A library might make it work for other containers, but it's not guaranteed. And there's a relationship between completeness of class types and implicit instantiations of class templates, but I haven't worked out exactly how that applies to this code. – aschepler Jun 01 '21 at 05:33

1 Answers1

3

The variable here is simply whether std::deque requires its element type to be complete when it is instantiated. (Of course it must be complete when certain member functions are instantiated, but that’s separate.) If it does, you end up needing your value_type before it’s declared, which produces the error observed. C++17 requires that std::vector support incomplete types, but says nothing about std::deque, which is why this varies per standard library.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76
  • 2
    The Standard does say one thing about `std::deque`, in the overall general statement that unless stated otherwise, using an incomplete type as a template argument for a template in the standard library results in undefined behavior. (An implementation which makes it work for `std::deque` anyway is a valid result of undefined behavior.) – aschepler Jun 01 '21 at 05:36
  • 2
    Yeah. Ain't UB a stinker? – user4581301 Jun 01 '21 at 05:37
  • I turned the `std::deque` into a pointer and now it works. Thank you! – JMRC Jun 01 '21 at 05:44