default arguments cannot be added to an out-of-line definition of a member of a class template

While trying to compile ccp4 with clang, I ran into the following error in the test case...

------------- outofline.cpp --------------------
template <typename realnum>
class covar_matrix
{
  public:

        void SetZeroRows(int,int,int,int,int,int); // specifies the order numbers of rows(=columns) for which the covariances should be 0.

  private:

};

// defines zero rows. If the first argument is negative, resets all no non-zero.
template <typename realnum>
void covar_matrix<realnum>::SetZeroRows( int r1=-1, int r2=-1, int r3=-1, int r4=-1, int r5=-1, int r6=-1 )
{
  int r[6] = {r1,r2,r3,r4,r5,r6};
  int i=0;
}

Hello,

  While trying to compile ccp4 with clang, I ran into the following error in the test case...

------------- outofline.cpp --------------------
template <typename realnum>
class covar_matrix
{
public:

       void SetZeroRows(int,int,int,int,int,int); // specifies the order numbers of rows(=columns) for which the covariances should be 0.

private:

};

// defines zero rows. If the first argument is negative, resets all no non-zero.
template <typename realnum>
void covar_matrix<realnum>::SetZeroRows( int r1=-1, int r2=-1, int r3=-1, int r4=-1, int r5=-1, int r6=-1 )
{
int r[6] = {r1,r2,r3,r4,r5,r6};
int i=0;
}

------------------------------------------------

[MacPro:~] howarth% clang -c outofline.cpp
outofline.cpp:16:46: error: default arguments cannot be added to an out-of-line definition of a member of a class template
void covar_matrix<realnum>::SetZeroRows( int r1=-1, int r2=-1, int r3=-1, int r4=-1, int r5=-1, int r6=-1 )
[...]

I assume this isn't a bug in clang. If so, what is the proper solution? Is it this change?

It is not a clang bug, at least not from my reading of the standard (FDIS 8.3.6p4: Adding default arguments later on is
only valid with *non-template* functions. Here we have a function template, since SetZeroRows is part of a class template).

The solution is to add the default parameters (the "-1" in your example) to the declaration of the function and to remove
them from its definition. This compiles with the current clang:

template <typename realnum>
class covar_matrix
{
public:

       void SetZeroRows(int = -1,int = -1,int = -1,int = -1,int = -1,int = -1); // specifies the order numbers of rows(=columns) for which the covariances should be 0.

private:

};

// defines zero rows. If the first argument is negative, resets all no non-zero.
template <typename realnum>
void covar_matrix<realnum>::SetZeroRows( int r1, int r2, int r3, int r4, int r5, int r6 )
{
int r[6] = {r1,r2,r3,r4,r5,r6};
int i=0;
}

// defines zero rows. If the first argument is negative, resets all no non-zero.
template <typename realnum>
void covar_matrix<realnum>::SetZeroRows( int r1, int r2, int r3, int r4, int r5, int r6 )
{
int r[6] = {r1,r2,r3,r4,r5,r6};
int i=0;
r1=-1;
r2=-1;
r3=-1;
r4=-1;
r5=-1;
r6=-1;
}

This most likely does not what you want: It does not specify default parameters, but sets r0-6 to -1 after
using them to initialize r.

In my opinion, this is a bug in ccp4. You should file a bug report there (with the above solution).

Hope that helps,
Jonathan