模板专门化:' Scalar '不命名类型

Template specialization: ‘Scalar’ does not name a type

本文关键字:类型 Scalar 专门化      更新时间:2023-10-16

我正在尝试实现complex标量的模板专门化,并且在Stackoverflow的帮助下,使用了std::enable_if_t及其穷人版本

#include <type_traits>
#include <complex>
// declarations
namespace Test {
  template<class Scalar>
    class A {
      public:
        A(const Scalar z);
        Scalar realPart();
      private:
        Scalar z_;
    };
}
// definitions
namespace Test {
  template<bool B, class T = void>
    using enable_if_t = typename std::enable_if<B,T>::type;
  template<class T> struct is_complex : std::false_type {};
  template<class T> struct is_complex<std::complex<T>> : std::true_type {};
  template<class Scalar>
    A<Scalar>::
    A(const Scalar z) : z_(z)
  { }
  template<class S = Scalar, enable_if_t<is_complex<S>{}>* = nullptr>
    Scalar
    A<Scalar>::realPart()
    {
      return z_.real();
    }
  template<class S = Scalar, enable_if_t<!is_complex<S>{}>* = nullptr>
    Scalar
    A<Scalar>::realPart()
    {
      return z_;
    }
}
int main() {
}

为c++ 11。但是,上面的代码将声明和定义分开,无法使用

进行编译。
test4.cpp:29:22: error: ‘Scalar’ does not name a type
   template<class S = Scalar, enable_if_t<is_complex<S>{}>* = nullptr>
                      ^

我不清楚这是怎么失败的。有提示吗?

在此代码中:

template<class S = Scalar, enable_if_t<is_complex<S>{}>* = nullptr>
Scalar A<Scalar>::realPart()
{
  return z_.real();
}

Scalar没有命名类型,因为它不是类型。这只是你一直在使用的模板参数的名字。你本来想写的是:

template<class Scalar, enable_if_t<is_complex<Scalar>{}>* = nullptr>
Scalar A<Scalar>::realPart()
{
  return z_.real();
}

然而,这也不起作用,因为A没有第二个模板非类型参数,而您试图传递它一个。你真正要做的是部分专门化成员函数A<Scalar>::realPart(),这在语言中是不可能的。

你需要做的是分派给一个知道该做什么的助手。比如:

template <class Scalar>
Scalar A<Scalar>::realPart() {
    return getRealPart(z_);
}

:

template <typename Scalar>
Scalar getRealPart(Scalar r) { return r; }
template <typename Scalar>
Scalar getRealPart(std::complex<Scalar> c) { return c.real(); }

对于更复杂的类型特征,我们会这样做:

template <class Scalar>
Scalar A<Scalar>::realPart() {
    return getRealPart(z_, is_complex<Scalar>{});
}

和以true_typefalse_type作为第二个参数的重载。在这种特殊情况下,这是不必要的。

我手头没有编译器,但我认为:

template<class S = Scalar, enable_if_t<is_complex<S>{}>* = nullptr>
A<Scalar>::
Scalar realPart()
{
  return z_.real();
}
应:

template<typename Scalar, enable_if_t<is_complex<Scalar>{}>* = nullptr>
//       ^^^^^^^^^^^^^^^                         ^^^^^^
typename Scalar A<Scalar>::realPart()
//^^^^^^^^^^^^^^^^^^^^^^^^^
{
  return z_.real();
}

…另一个定义也是一样