2

The following code compiles.

matrix.h before template

template<typename T>
class Matrix
{
public:
    //...
    unique_ptr<Matrix<T>> Test() const;
};

matrix.cpp before template

template<typename T>
unique_ptr<Matrix<T>> Matrix<T>::Test() const
{
    unique_ptr<Matrix<T>> a{ new Matrix<T>{ 1, 1 } };
    return std::move(a);
}

I wanted to use a typedef (using) to shorten things as I thought it'd be more readable but my changes cause errors. Here are the relevant changes.

matrix.h after template

template<typename T>
class Matrix
{
public:
    //...
    MatrixUniq<T> Test() const;
};

template<class T> using MatrixUniq = unique_ptr<Matrix<T>>;

matrix.cpp after template

template<typename T>
MatrixUniq<T> Matrix<T>::Test() const
{
    MatrixUniq<T> a{ new Matrix<T>{ 1, 1 } };
    return std::move(a);
}

Compiling after these changes are made crashes the VC++ compiler twice, but also generates a few errors:

Error   C2143   syntax error: missing ';' before '<'    
Error   C4430   missing type specifier - int assumed. 
Error   C2238   unexpected token(s) preceding ';'
Error   C1903   unable to recover from previous error(s);

What's wrong with my typedef implementation? Thanks.

Edit: I'm using VS2015. I'm building a static library. At the bottom of matrix.cpp I have:

template class VMatrix<double>;
Phlox Midas
  • 4,093
  • 4
  • 35
  • 56

3 Answers3

4

You are using the MatrixUniq<T> alias before having defined it.

Move the using inside the class:

template<typename T>
class Matrix
{
public:
    template<class U> using MatrixUniq = std::unique_ptr<Matrix<U>>;

    MatrixUniq<T> Test() const;
};

And change the definition accordingly:

template<typename T>
Matrix<T>::MatrixUniq<T> Matrix<T>::Test() const
{
    return MatrixUniq<T>{ new Matrix<T>{ 1, 1 } };
}

Or if you want to have it in the global namespace, define it before the class definition after a forward declaration on the class:

template<typename T>
class Matrix;

template<class T> using MatrixUniq = std::unique_ptr<Matrix<T>>;

template<typename T>
class Matrix
{
public:
    //...
    MatrixUniq<T> Test() const;
};

Also you don't need to explicitly do a std::move when returning local variables. Local variables that are returned are automatically moved by default.

Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Emil Laine
  • 41,598
  • 9
  • 101
  • 157
  • I think you're correct. Is there a shorter way of doing it rather than the lengthy Matrix::MatrixUniq. Preferably some way that other classes could see it so in other classes I could say: `MatrixUniq m = Foo();`? – Phlox Midas Aug 08 '15 at 18:59
  • @PhloxMidas See the edit I added about having it directly in the global namespace. – Emil Laine Aug 08 '15 at 19:00
  • That compiled straight off. Thank you very much. – Phlox Midas Aug 08 '15 at 19:02
3

try this:

template<typename T>
class Matrix
{
public:
    using unique_ptr_type = std::unique_ptr<Matrix>;
    //...
    unique_ptr_type Test() const;
};

template<class T> using MatrixUniq = typename Matrix<T>::unique_ptr_type;

template<typename T>
typename Matrix<T>::unique_ptr_type Matrix<T>::Test() const
{
    return unique_ptr_type(new Matrix());
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Thank you for replying. It could've gone to any of the answers, I just saw the other one first but I really appreciate your help. I gave an upvote. Thanks again. – Phlox Midas Aug 08 '15 at 19:03
1

Always make sure to declare templates above the code which will be using it.

Also this snippet:

template<class T> using MatrixUniq = unique_ptr<Matrix<T>>;

might not be a correct implementation.

Here's how you can declare a type definition in c++.

typedef <type> <var_name>

Here's another example using an 'Alias Template'

template<typename T>
using MyVector = std::vector<T, MyCustomAllocator<T>>;

The rest of the code is for you to debug.

See this relevant discussion here:

How to typedef a template class?

navi
  • 11
  • 1