为什么不允许成员函数的模板专业化?

时间:2018-12-19 16:37:47

标签: c++ templates standards

如果我有一些琐碎的事情,例如(为澄清起见,我并不是说这是一个很好的实现,只需举一个示例来演示成员函数的部分模板特化失败):

template <typename T, typename U>
class BankAccount
{
  T money;
  U interestRate;
public:
  BankAccount(T money, U interestRate) :
    money(money), interestRate(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 <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();
}

等不幸的是,C ++标准不允许这样做:

  

14.5.5.3.1。类模板部分专业化成员的模板参数列表应与类模板部分专业化的模板参数列表匹配。类模板部分专业化成员的模板参数列表应与类模板部分专业化的模板参数列表相匹配。

因此,(我知道的)唯一的解决方案是使用类型特征或使用样板代码重现整个类。做出此决定的依据是合理的,还是因为需求不足或其他原因而在C ++中根本不存在这种东西?

1 个答案:

答案 0 :(得分:1)

因为它不是您编写的成员函数的模板专业化。这是该课程的专业化。因此,代码应如下所示(我添加了一个通用基类,您不必为所有规范定义成员):

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();
}