c++templatesc++20dependent-name

error: type/value mismatch in template parameter list for std::variant


The following code doesn't work if class some_class is templated. So my guess is that I have to put the template specifier in front of something, but I don't really know where? I tried putting it in front of state::base and state::error types within the variant definition, but this doesn't work. Where do I put it and why?

Demo

#include <variant>

template <typename T>
class some_class
{
    void do_something() {
        struct state {
            struct base{};
            struct error{};
        };

        std::variant<state::base, state::error> fsm{};
    }
};

int main() {}

Error:

<source>:12:47: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... _Types> class std::variant'
   12 |         std::variant<state::base, state::error> fsm{};
      |                                               ^
<source>:12:47: note:   expected a type, got 'some_class<T>::do_something()::state::base'
<source>:12:47: error: type/value mismatch at argument 1 in template parameter list for 'template<class ... _Types> class std::variant'
<source>:12:47: note:   expected a type, got 'some_class<T>::do_something()::state::error'

Solution

  • The compiler considers state::base and state::error to be dependent (on the template arguments), in which case they would require prefixing with typename so that they are considered types while parsing the class template definition.

    However, intuitively these names/types seem like they shouldn't be dependent. Although the type is a different one for each specialization of the enclosing class template, it is guaranteed that state::base will always name and refer to a known type in the function definition for every instantiation of the enclosing template. This can't be changed e.g. via explicit or partial specialization.

    This seems to be an open CWG issue (CWG 2074). The standard currently does not say that these names are dependent. They would be dependent only if the local classes contained a dependent type (see [temp.dep.type]/9.5), but they don't do that in your case. Still it seems some compilers consider these types to be dependent.

    So your solution is to prefix them with typename even if that is probably not required or intended per standard.