2

When I compile this code (with Visual Studio 2017):

template<class MostDerived>
class BaseClass
{
public:
    typename MostDerived::Units DoStuff()
    {
        MostDerived::Units units;

        return units;
    }
};

class DerivedClass : public BaseClass<DerivedClass>
{
public:
    enum class Units
    {
        Unit1
    };
};

void Invoke()
{
    DerivedClass derivedClass;
    DerivedClass::Units units = derivedClass.DoStuff();
}

I get an error:

C2039: 'Units': is not a member of 'DerivedClass'.

Experimenting with it, I've determined that the error occurs when DerivedClass::Units is used as either the result or a parameter to DoStuff() (so returning the result in a by-reference variable doesn't fix the error). I can use Units in the body of the function with no error.

Is this behavior consistent with C++ 17 or is it a bug in Visual C++?

Dean Seo
  • 5,486
  • 3
  • 30
  • 49
ash
  • 21
  • 2
  • 3
    Possible duplicate of [Use Curiously Recurring Template Pattern (CRTP) with additional type parameters](https://stackoverflow.com/questions/5680263/use-curiously-recurring-template-pattern-crtp-with-additional-type-parameters) – Jodocus Nov 26 '17 at 21:40
  • I fail to see how this is a duplicate of the question you linked. My question has no additional template parameters and I don't see any useful correlation between the questions. Why do you think they are duplicates (other than both refer to CRTP)? – ash Nov 26 '17 at 23:25
  • Both questions are referred to incomplete types. Both problems can be solved by using a traits pattern. – Jodocus Nov 27 '17 at 00:10
  • I can see where traits might workaround the issue, but I don't want to make the external interface more confusing for what is relatively small benefit (the shared code I'm trying to factor out is small). I have changed the question to ask if this is consistent with C++ 17. – ash Dec 04 '17 at 03:00
  • I can get a comparable error on g++, so it's unlikely to be a bug. It looks like you'll probably need a workaround to get this to play nice. – Silvio Mayolo Dec 04 '17 at 03:03
  • g++ and clang++ reject this with errors very similar to that of vc++ so it is unlikely to be a bug. – n. m. could be an AI Dec 04 '17 at 07:58
  • @Jodocus This is not really a duplicate because this question tries to utilize an incomplete type as a function return type which is different from that question, as tries to utilize an incomplete type only for declarations. Even though both of them can be dealt with using traits this particular question has a simpler solution. – user7860670 Dec 04 '17 at 08:00
  • I agree with @VTT. This question is *slightly* different from the suggested possible duplicate one. They just coincidentially happen to have the same workaround. (Not to mention that it's just answered with a (better and) simpler approach.) – Dean Seo Dec 04 '17 at 08:48

1 Answers1

4

You can fix it using automatic return type deduction. Using Units inside of function is not an error because instantiation of BaseClass<DerivedClass> will only instantiate declarations, not definitions. DoStuff body gets instantiated when it is actually called and at that point Units is not incomplete anymore.

auto DoStuff()
{
    typename MostDerived::Units units{};
    return units;
}

online compiler

user7860670
  • 35,849
  • 4
  • 58
  • 84