【问题标题】:C++ How Do You Pass Multiple Parameters?C++ 如何传递多个参数?
【发布时间】:2016-06-03 02:30:45
【问题描述】:

假设我有一个概率类,它有一个计算数组平均值的方法。因为这个方法可能会传递一个浮点数、双精度数、整数等数组,所以我认为将这个方法设为模板方法是合适的。

但是在传递数组时,我必须定义数组的类型和数组的长度。所以我的问题是:如何配置模板以接受两个输入?我参考了网络,但没有看到一个很好的例子。

  • 定义模板以接受整数、浮点数等参数是否有效?

我已经在下面发布了我的代码

概率标题

#ifndef COFFEEDEVMATH_PROBABILITY_H
#define COFFEEDEVMATH_PROBABILITY_H

class Probability
{
    public:
         Probability(void);
        template <typename T, int N>
        void ExpectedValueDataSet(const std::array<T, N>& data)
        {
            T test = data[0]; // This is irrelevant, but simply a place holder example.
        }

    protected:
    private:
};

#endif // COFFEEDEVMATH_PROBABILITY_H

主要

#include <iostream>
#include <Probability.h>

int main()
{

    float hoor[] = {3, 3, 1, 1};
    Probability prob;
    prob.ExpectedValueDataSet(hoor, 4);

}

【问题讨论】:

  • 应该是整个类,而不是一个方法。
  • 对于初学者来说,int 不是std::array 的第二个模板参数,所以不能推导出来。类型为size_t
  • 为什么?我觉得拥有一个可以对您扔给它的不同类型数据进行操作的单个“概率对象”会更合适。我试图在 C++ 中做的事情不合法吗?
  • 为什么不使用std::vectorstd::array 而不是C 样式的数组?那么你不必担心传递长度,它们是容器的一部分。
  • @Teague 如果您想要一个不包含任何状态的概率对象(没有成员变量,只是一组具有相关目的的函数),您可以将所有函数设为静态并且从不实例化该对象而是将其命名空间用作对所有内容进行分组的逻辑方式。

标签: c++ arrays templates c++11


【解决方案1】:

定义模板接受整数、浮点数等参数是否有效?

完全没问题。但是要传递一个数组,你必须有一个数组。

std::array<float,4> hoor2 = {3.0f, 3.0f, 1.0f, 1.0f};

在相应的模板中你必须使用size_t,而不是int

template <typename T, size_t N>
void ExpectedValueDataSet(const std::array<T, N>& data) {}

如何配置模板以接受两个输入?

只需添加一个附加参数。要传递指针和长度,您需要创建一个接收指针和长度的模板

template <typename T>
void ExpectedValueDataSet( T const * data, int N){}

对于 c 风格的数组还有一种特殊的语法,它允许您传递它们而无需指定长度,因为该参数将从类型中推导出来。

template <typename T, size_t N >
void ExpectedValueDataSet( const T (&data)[N]) { }

我们在一起

class Probability
{ 
public:
    template <typename T, size_t N>
    void ExpectedValueDataSet(const std::array<T, N>& data) {}

    template <typename T>
    void ExpectedValueDataSet( T const * data, int N){}

    template <typename T, size_t N>
    void ExpectedValueDataSet(const T (&data)[N]){};
};

查看实时工作示例here

【讨论】:

  • 我认为他的模板的int N 旨在成为数组大小。
  • @kfsone 对,忘记了 c 样式数组。已更正。
【解决方案2】:

问题是您将源数组定义为糟糕的 C 数组,而不是 std::array。如果将源数组定义为std::array,则不会出现此问题。

另外,不需要像您的示例那样传递长度。

【讨论】:

    【解决方案3】:

    请注意,您正在尝试将旧的纯 C 数组 float hoor[] 传递给带有与纯 C 数组不直接兼容的 std::array&lt;T,N&gt; 类型参数的函数。

    将纯 C 数组作为引用传递的正确语法是:

    template <size_t N, typename T>
    void ExpectedValueDataSet(const T (&data)[N])
    {
        T test = data[0];
    }
    

    使用示例:

    float hoor_f[] = {3, 3, 1, 1};
    ExpectedValueDataSet(hoor_f);
    
    int hoor_i[] = {3, 3, 1, 1};
    ExpectedValueDataSet(hoor_i);
    

    【讨论】:

      【解决方案4】:

      最终,我感觉以下是您应该做的事情:

      template<typename C>
      typename C::value_type average(C const& c)
      {
          return std::accumulate(std::begin(c), std::end(c), C::value_type{}) / c.size();
      }
      
      1. 尽可能避免使用 C 样式的数组。
      2. 尽可能支持std::vector
      3. std 的所有容器的通用性很好。

      上面的代码满足这三个条件,并且可以和下面的例子一起使用:

      std::vector<double> vd = { 0., 1., 3., 4.4 };
      std::array<float, 4> af = { 3.f, 5.f, 6.f };
      std::list<int> li = { 1, 2, 3 };
      

      【讨论】:

        【解决方案5】:

        实际上,您可以有多个模板参数,但 C++ 模板提供了更大的灵活性,您可以直接避免指定您正在处理一个数组,并假设您可以访问 size() const 方法、value_type typedef 和并重载operator[]

        这就足够了,所以代码会变成这样:

        template <typename T>
        void calculate(const T& data)
        {
            size_t length = data.size();
            using type = typename T::value_type;
            type value = data[0];
            cout << length << " " << value << endl;
        }
        

        这对您的实现来说更通用,它可以与支持上述特征的所有类一起使用,甚至不用担心它是std::array,还是std::vector 或其他什么。

        【讨论】:

        • 其实通用的处理方式就是迭代器。
        • @Puppy:如果 OP 需要处理自定义数据结构,定义 size() 方法、operator[]typedef 编写自定义迭代器要简单得多。实际上学习如何正确编写随机访问迭代器根本不是那么基本。
        • 除了基本上所有的数据结构都已经提供了迭代器(并且有充分的理由)
        【解决方案6】:

        像这样将容器传递给模板函数。

        #include <iostream>
        
        template<typename T>
        double average(T t) {
            auto tmp = 0.0;
            for (auto &i : t) {
                tmp += i;
            }
            return tmp/t.size();
        }
        
        using namespace std;
        
        int main(int argc, char const *argv[])
        {
            auto a = {1.0, 1.1, 1.2, 1.3};
            auto b = {2, 3, 4, 5};
            auto x = average(a);
            auto y = average(b);
            cout << "x: " << x << endl;
            cout << "y: " << y << endl;
            return 0;
        }
        

        x:1.15
        y: 3.5

        并使用 lambda。 lambdas 中的 auto 关键字需要 C++14 及更高版本。

        auto average = [](auto v){
            auto tmp = 0.0;
            for (auto& i : v) {
                tmp += i;
            }
            return tmp/v.size();
        };
        auto a = {1.1, 1.2, 1.3, 1.4};
        auto b = {2, 3, 4, 5, 6, 7, 8, 9};
        auto x = average(a);
        auto y = average(b);
        cout << "x: " << x << endl;
        cout << "y: " << y << endl;
        

        x:1.25
        y: 5.5

        【讨论】:

          猜你喜欢
          • 2012-08-13
          • 2010-10-17
          • 2021-12-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-12
          • 2017-12-13
          • 1970-01-01
          相关资源
          最近更新 更多