【问题标题】:adding arrays of different types (c++)添加不同类型的数组(C++)
【发布时间】:2014-06-03 01:01:24
【问题描述】:

我需要动态创建包含不同数值类型的数组,包括 char、int、unsigned int、float、double。我希望能够创建这些数组中的任意两个,并假设它们的长度相同,实现算术运算符,例如 operator+=

我已经能够将数组实现为模板,但我不知道如何实现任何算术运算符,因为在编译时我不知道其他数组的类型是什么,甚至当第一个数组被创建(我会知道我正在构建的数组的类型)。我查看了 std::array,但它不支持算术运算符。另一种绝对不优雅(但确实有效)的替代方法是实现一系列特定于类型的运算符,例如

MyArray<V> operator+ (const MyArray<float>& addend) const;
MyArray<V> operator+ (const MyArray<double>& addend) const;
MyArray<V> operator+ (const MyArray<int32>& addend) const;
MyArray<V> operator+ (const MyArray<int16>& addend) const;

感谢您的建议。

【问题讨论】:

  • 这些运营商需要做什么?如果它们是简单的算术,那你为什么要自己写呢?
  • 这可能是运算符重载不是一个好选择的实例,恕我直言。 std::transform(this-&gt;begin(), this-&gt;end(), addend.end(), output-&gt;begin(), std::plus&lt;V&gt;());
  • 为了展开,二元运算符重载只有在你能保证它们有意义时才有意义。这从表面上看似乎很简单,但您需要保证 a+b==b+a 之类的东西,而您的情况显然没有(返回类型不同意)。此外,您似乎正在为每个运算符分配一个新数组,这将产生不必要的开销。
  • @MadScienceDreams 这并不总是正确的。例如对于矩阵类,二元运算符 * 会根据输入的顺序给出不同的答案。
  • @CoffeeandCode 是的,我同意我不够清楚。另一个例子,其中操作顺序对连接类型“加号”很重要。最大的问题是,无论做什么,它必须有意义,这不是微不足道的。对于数学加法运算符,a+b 应该等于 b+a

标签: c++ arrays templates


【解决方案1】:

好吧,从我对这个线程中所有内容的 cmets 来看,这可能已经很明显了,这对我来说是一个特别的痛处。这是有充分理由的,我曾经和你一样。我当时想,我可以重载运算符!惊人的!重载所有操作员(这是使用自定义图像容器类型)。过了一会儿,一些事情变得清晰了:

  1. 运算符很难正确声明,尤其是模板化的。
  2. 模板化操作符的类型不能显式设置,只能隐式设置。
  3. 操作顺序始终没有意义。
  4. 操作员必须使用异常作为其“失败”模式,这在所有情况下都不理想,或者如果可以在编译时检测到失败,则使用“enable-if”类型语法。
  5. 运算符的含义很难记录/阐明。对操作员应该“做什么”的不同解释让人很难弄清楚。 (MyArray&lt;T&gt;+MyArray&lt;J&gt; 应该像 T+J 那样作为成员加号工作,还是应该像 'string+string' 这样的连接工作?)
  6. 运算符必须按值返回,如果您的移动设置不正确/您不是在 C++11 中/由于任何原因没有发生返回值省略,这可能会导致开销。
  7. 总的来说,编写自己的容器类型是重做 STL 已经完成的大量工作的好方法。

你可以这样做(在命名空间范围内)(假设你有一个可用的模板转换运算符)

template <typename T, typename J>
MyArray<decltype(T()+J())> operator+(const MyArray<T>& x,const MyArray<J>& y)
{
   using K=decltype(T()+J());
   MyArray<K> ret(x.size());//or something?
   for (size_t i = 0; i < x.size(); i++) {ret[i]=x[i]+y[i];}//could replace with foreach
   return ret;
};

尽管将以下内容与向量一起使用更有意义。如果需要,您可以将其包装在“添加”调用中。

std::vector<T> a;//or whatever
std::vector<J> b;//or whatever
std::vector<K> c(a.size());//note: you can still use the decl type here, OR just define it to whatever you actually want it to be
std::transform(a.begin(), a.end(). b.begin(), c.begin(), std::plus<K>());

如果您想在所有地方都这样做,并且正在尝试创建一个矩阵数学库,请使用像 Eigen 这样的库,它会为您节省大量工作,它将被强类型化为矩阵和不是通用集合,它将使用 Eigen 团队拥有的全部数学知识来完成。

【讨论】:

    【解决方案2】:

    你可以多使用一个模板参数:

    template<class V, class T> MyArray<V> operator+ (const MyArray<T>& addend) const;
    

    那么演员将始终根据您的主数组类型。

    【讨论】:

    • 不,它被强制转换为任意的第一个参数。假设 A 是 MyArray&lt;int&gt;,B 是 MyArray&lt;float&gt;。 A+B 将返回一个MyArray&lt;int&gt;(基础数学将计算为float,然后转换为int)。 B+A 将返回 MyArray&lt;float&gt;A[0]+B[0] 将返回 floatB[0]+A[0] 将返回 float。您可能应该使用 C++ 的提升规则或不使用无法显式设置模板参数的运算符。
    【解决方案3】:

    您可能必须通过某些类型特征选择的结果类型来分派您的操作。

    简化为数字(无向量):

    #include <iostream>
    
    template <typename T>
    struct Number {
        T value;
        Number(T value) : value(value) {}
    
        template <typename U>
        explicit Number(U value) : value(value) {}
    
        operator T () const { return value; }
    };
    
    #define C_PLUS_PLUS_11 (201103L <= __cplusplus)
    
    template <typename U, typename V>
    struct binary_operation_traits {
        #if C_PLUS_PLUS_11
        typedef decltype(U() + V()) result_type;
        #endif
    };
    
    #if ! C_PLUS_PLUS_11
    template <typename T>
    struct binary_operation_traits<T, T> {
        typedef T result_type;
    };
    
    template <>
    struct binary_operation_traits<int, float> {
        typedef float result_type;
    };
    
    template <>
    struct binary_operation_traits<int, double> {
        typedef double result_type;
    };
    
    // And so on ...
    
    #endif
    
    template <typename U, typename V>
    Number<typename binary_operation_traits<U, V>::result_type>
    operator + (const Number<U>& a, const Number<V>& b) {
        typedef typename binary_operation_traits<U, V>::result_type result_type;
        return Number<result_type>(result_type(a) + result_type(b));
    }
    
    int main ()
    {
        Number<int> a(1);
        Number<double> b(1.5);
        std::cout << a + b << '\n';
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多