Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is template specialization of member functions not allowed?

If I had something trivial such as (and to clarify, I am not suggesting this is a good implementation, simply an example to demonstrate partial template specialization failure on member functions):

template <typename T, typename U>
class BankAccount
{
  T money;
  U interestRate;
public:
  BankAccount(T money, U interestRate) :
    money(money), interestRate(interestRate)
  {}

  void showMeTheMoney();
};

I would not be able to specialize each function by doing:

// invalid code
template <typename U>
void BankAccount <int, U>::showMeTheMoney()
{
  printf("$%d.00 interest: %f\n", money, interestRate);
}

template <typename U>
void BankAccount <long, U>::showMeTheMoney()
{
  printf("$%l.00 interest: %f\n", money, interestRate);
}

template <typename U>
void BankAccount <float, U>::showMeTheMoney()
{
  printf("$%.2f interest: %f\n", money, interestRate);
}

template <typename U>
void BankAccount <double, U>::showMeTheMoney()
{
  printf("$%.2f interest: %f\n", money, interestRate);
}

int main(int argc, char *argv[])
{
  BankAccount<double, float> b(500, 0.03);
  b.showMeTheMoney();
  BankAccount<std::uint64_t, float> c(1234, 0.01);
  c.showMeTheMoney();
}

etc. Unfortunately C++ standards do not allow this:

14.5.5.3.1. The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization. The template argument list of a member of a class template partial specialization shall match the template argument list of the class template partial specialization.

So instead the only solutions (that I know of) are to use type traits or reproduce the entire class with boilerplate code. Is there a rationale behind this decision, or is this something that simply does not exist in C++ because there isn't enough demand, or some other reason?

like image 979
Michael Choi Avatar asked Dec 19 '18 16:12

Michael Choi


1 Answers

Because it is not a template specialization of a member function that you have written. It is specialization of the class. Hence, the code should look like this (I added a common base class that you don not have to define the members for all specifications):

template <typename T, typename U>
class BankAccountBase
{
protected:
    T money;
    U interestRate;

public:
    BankAccountBase(T money, U interestRate) :
        money(money), interestRate(interestRate)
    {}
};

template <typename T, typename U>
class BankAccount
{
    T money;
    U interestRate;
public:
    BankAccount(T money, U interestRate) :
        money(money), interestRate(interestRate)
    {}

    void showMeTheMoney();
};

template <typename U>
class BankAccount <int, U> : public BankAccountBase <int, U>
{
public:
    BankAccount(int money, U interestRate) :BankAccountBase(money, interestRate) { }
    void showMeTheMoney();
};

template <typename U>
class BankAccount <long, U> : public BankAccountBase <long, U>
{
public:
    BankAccount(long money, U interestRate) :BankAccountBase(money, interestRate) { }
    void showMeTheMoney();
};
template <typename U>
class BankAccount <float, U> : public BankAccountBase <float, U>
{
    BankAccount(float money, U interestRate) :BankAccountBase(money, interestRate) { }
public:
    void showMeTheMoney();
};
template <typename U>
class BankAccount <double, U> : public BankAccountBase <double, U>
{
public:
    BankAccount(double money, U interestRate) :BankAccountBase(money, interestRate) { }
    void showMeTheMoney();
};

template <typename U>
class BankAccount <long long, U> : public BankAccountBase <long long, U>
{
public:
    BankAccount(long long money, U interestRate) :BankAccountBase(money, interestRate) { }
    void showMeTheMoney();
};


// invalid code
template <typename U>
void BankAccount <int, U>::showMeTheMoney()
{
    printf("$%d.00 interest: %f\n", money, interestRate);
}

template <typename U>
void BankAccount <long, U>::showMeTheMoney()
{
    printf("$%l.00 interest: %f\n", money, interestRate);
}

template <typename U>
void BankAccount <long long, U>::showMeTheMoney()
{
    printf("$%l.00 interest: %f\n", money, interestRate);
}

template <typename U>
void BankAccount <float, U>::showMeTheMoney()
{
    printf("$%.2f interest: %f\n", money, interestRate);
}

template <typename U>
void BankAccount <double, U>::showMeTheMoney()
{
    printf("$%.2f interest: %f\n", money, interestRate);
}

int main(int argc, char *argv[])
{
    BankAccount<double, float> b(500, 0.03);
    b.showMeTheMoney();
    BankAccount<long long, float> c(1234, 0.01);
    c.showMeTheMoney();
}
like image 88
Jürgen Avatar answered Oct 31 '22 05:10

Jürgen