【问题标题】:C++: Default initialize an integral type in a template functionC ++:默认初始化模板函数中的整数类型
【发布时间】:2013-08-08 07:16:19
【问题描述】:

出于教育目的,我正在编写自己的 C++ 数值向量模板类。我希望能够为两个向量的点积编写 (v, w) 并因此重载operator,(),如下所示:

template<class T>
const T Vector<T>::operator,(const Vector<T>& v) const
{
    assertEqualSize(v);

    T t;
    for(size_t i=0; i<numElements; i++) {
        t += elements[i] * v[i];
    }
    return t;
}

我现在的问题是:如何使用合理的值正确初始化 t(例如 0.0 用于 Vector&lt;double&gt;)?我尝试了T t();,但随后 g++ 告诉我,例如,“double(*)()”不能在 return 语句中转换为“const double”,并且operator+=() 不会为“(double(),双)”。

非常感谢!

【问题讨论】:

  • 对点积使用(v,w) 相当奇怪。为什么不简单地重载*,即点积的v*w? (这就是我使用的)。在 3D 中,可以使用^ 实现矢量积。当然,标量或矩阵的乘法也可以使用*(的另一个重载)来实现。
  • 我同意重复使用逗号运算符 si 不是一个好主意。会导致代码混乱。不幸的是,重新使用* 也不是一个好主意,因为它不是明确的,交叉产品是一个明显的候选者。我通常为涉及向量的二元运算提供函数。

标签: c++ templates


【解决方案1】:

您需要的称为值初始化,它具有对内置类型进行零初始化的效果:

T t{};     // C++11
T t = T(); // C++03 and C++11

这不起作用的原因

T t();

它是一个名为t的无参数函数的声明,返回一个T

【讨论】:

  • 这不是 MVP 的模板版本吗?
  • @Borgleader,MVP 更多的是Foo foo(Bar());,但是是的。
  • @o.svensson 没什么可感到愚蠢的:这是该语言的两个“特殊”功能:解析所有看起来像函数的东西,而不是初始化默认构造的内置类型。
  • @Walter 代码中没有任何内容强制 T 成为内置类型。所以这可能会引入错误。
  • 仍然假设T() 在相关意义上为零。 IE。 a+=T() 对所有 a 都是无操作的,包括 a==T()
【解决方案2】:

当简单的值初始化调用默认构造函数和因此可能无法进行零初始化。如果您的意图不是内置类型T,我会感到惊讶,但是您的代码的用户可能有其他想法......您应该防范这种情况,例如通过 SFINAE:

template<class T>
struct is_complex { static const bool value = false; };
template<class U>
struct is_complex<std::complex<U>> : std::is_floating_point<U> {};

template<class T>
typename
std::enable_if<std::is_floating_point<T>::value || is_complex<T>::value,
               T>::type
T Vector<T>::operator,(const Vector<T>& v) const
{
   T t{};  // value-initialisation is now guaranteed to be zero-initialisation
   /* ... */
}

当然,这种类型的 SFINAE 可以作为一个整体应用于class Vector&lt;T&gt;(而不是应用于选定的方法)。


澄清一下:这基本上将可能的类型 T 限制为 6 种允许的类型(floatdoublelong double 和相应的 std::complex&lt;&gt; 类型)。当然,可以允许整数类型,但如果您想要对整数向量进行向量运算,我会感到惊讶。

【讨论】:

  • 没有办法防范用户定义类型的默认构造函数不对其元素执行零初始化。你的代码如何保证这样的零初始化?
  • @juanchopanza 对于此类类型,SFINAE 禁用该功能。只允许使用浮点类型或std::complex&lt;floating-point type&gt;
  • 重点是如何识别这些类型?您需要知道它们的默认构造函数的内部结构,并确定它们不是零初始化应该是的东西。我看不出 SFINAE 会如何做到这一点。
  • @juanchopanza 你没听懂。我不使用 SFINAE 禁用没有零初始化的类型。相反,我使用 SFINAE 来启用浮点类型(和std::complex&lt;&gt;)。只需阅读代码。
  • 但是没有必要,伙计。为什么你只想启用浮点类型和 std::complex??
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-19
  • 2012-09-15
  • 2017-12-30
  • 2012-03-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多