【问题标题】:Template specialization: ‘Scalar’ does not name a type模板特化:“标量”没有命名类型
【发布时间】:2015-06-09 18:40:10
【问题描述】:

我正在尝试为complex 标量实现模板特化,并且使用the help of 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>
                      ^

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

【问题讨论】:

  • 这是真的,它是一个模板参数,总是(在你的例子中)
  • 嗯,我不太明白。如果删除定义中的特化,它编译得很好,那么Scalarnot name a type呢?

标签: c++ templates c++11 c++14 template-specialization


【解决方案1】:

在这段代码中:

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&lt;Scalar&gt;::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 作为第二个参数的重载。在这种特殊情况下,这是不必要的。

【讨论】:

  • 我看到编译成功了,太好了!如果专精是Scalar = std::complex&lt;double&gt;,周围有std::complex&lt;Scalar&gt; 有点讨厌,但我想这不会太伤人。
【解决方案2】:

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

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

...其他定义也一样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    相关资源
    最近更新 更多