-1

EDIT: Some people suggest that this is a duplicate of this question. This is NOT the case as that question is about "How to use a nested struct/class type as a return value, in a template class" (the literal title of that question) and my question is about two separate templated classes (not nested) and how I can use a typedef to refer to a member when those classes share template parameters. I have changed the title to hopefully make this more clear.

In the following example showing a templated rectangle class:

template<typename CoordinateT>
class Rect{
private:
    CoordinateT x1;
    CoordinateT y1;
    CoordinateT x2;
    CoordinateT y2;
public:
    constexpr Rect() noexcept : x1(0), y1(0), x2(-1), y2(-1) {}
    constexpr Rect(CoordinateT left, CoordinateT top, CoordinateT width, CoordinateT height) noexcept;

};

, the templated rectangle class implementation:

template<typename CoordinateT>
constexpr inline Rect<CoordinateT>::Rect(CoordinateT aleft, CoordinateT atop, CoordinateT awidth, CoordinateT aheight) noexcept
    : x1(aleft), y1(atop), x2(aleft + awidth - 1), y2(atop + aheight - 1) {}

, a templated space class:

template<typename CoordinateT>
class Space
{
public:
    typedef Rect<CoordinateT> rectType; // A: WORKS
    
public:
    Space();
    
public:
    rectType bounds(); // B: WORKS

};

and the templated space class implementation:

template<typename CoordinateT>
rectType Space<PixelT, CoordinateT>::bounds(){ // C: ERROR, recType not available here
    // [....] calculate bounds in x1, y1, x2 ,y2
    return rectType(x1,y1,x2-x1,y2-y1); // D:WORKS
}

I want to shorten my typing of the return type for the bounds() memeber function by using a typedef.

However this fails to compile with the following message:

"Unknown type 'rectType'"

(See line marked C: ERROR above)

Why does this not work, and how can I have my cake an eat it too in this scenario?

Mr. Developerdude
  • 9,118
  • 10
  • 57
  • 95
  • `template Space::rectType Space::bounds(){` seems to be the correct code. – john Mar 18 '23 at 19:14
  • The return type of an out of class member function definition is not in the scope of the class. So any reference to any name declared inside the class must be fully qualified, i.e. `Space::rectType`. – john Mar 18 '23 at 19:18
  • @john: actually I tried that and that did not work either. But the first answer wuth the new syntax (auto xxxx -> rectType{} ) worked – Mr. Developerdude Mar 18 '23 at 19:21
  • Possibly you also need `typename`, `typename Space::rectType`, not certain about that. – john Mar 18 '23 at 19:22
  • @JaMiT: It clearly does not even resemble the question you suggested. I have therefore left this question unchanged. Thank you. – Mr. Developerdude Mar 18 '23 at 22:02
  • To me your question looks exactly the same as the question suggested by JaMiT. – n. m. could be an AI Mar 18 '23 at 22:18
  • @LennartRolland *"It clearly does not even resemble the question you suggested"* **???** 1) Define a type within a class template -- present in both. 2) Declare a member function returning that type -- present in both. 3) Define that member function outside the class definition -- present in both. 4) Compiler choking on the return type in that definition -- present in both. *How many similarities do you require before you see a resemblance?* – JaMiT Mar 18 '23 at 22:24
  • *"my question is about two separate templated classes (not nested) and how I can use a typedef to [make a nested type aliasing one of those classes and thereby make my question a match for the duplicate]"* – JaMiT Mar 19 '23 at 03:32

1 Answers1

2

Everything lexically before the name of the class in the declarator-id (Space<PixelT, CoordinateT>::bounds) of the out-of-class definition is not looked up in the scope of the class.

If you want to have the return type be looked up in the scope of the class, where the typedef can be found, you can use the new-style return type declaration form:

template<typename CoordinateT>
auto Space<PixelT, CoordinateT>::bounds() -> rectType
{ /*...*/ }

Otherwise you need to qualify rectType with the class in which it should be looked up:

template<typename CoordinateT>
typename Space<PixelT, CoordinateT>::rectType Space<PixelT, CoordinateT>::bounds()
{ /*...*/ }

typename is additionally required here, because Space<PixelT, CoordinateT> is dependent (on a template parameter), so the compiler needs to be told that Space<PixelT, CoordinateT>::rectType is a type name rather than a data member or member function, which the compiler can't know before instantiation of the template, but needs to know in order to parse the declaration. See this question for details.

user17732522
  • 53,019
  • 2
  • 56
  • 105