为什么通过值传递这种可变大小参数是不可能的?

时间:2010-11-19 09:23:59

标签: c++ compiler-construction standards parameter-passing

我们有如下结构:

template<size_t size>
class Container{
 public:
  char characters[size];
};

我们有如下功能:

template <size_t size>
void function(Container<size> input,size_t Size){
 //all instances do exactly same thing and with regard to Size that determines the size of object
}

现在在C ++中,对于每个大小的值,将创建一个不同的函数实例,并且显然在这种情况下不正确,因为所有实例都做同样的事情,为了避免这种情况,第一个函数参数应该是一个指针(char *指针)代替一个对象,以便接受任何大小的任何数组,从而消除了模板化函数的需要,但我很好奇有一个函数接受像上面那样C ++不允许的可变大小参数是不可能的所有实现和生成程序集,或以某种方式导致速度/内存方面的低效实现?

6 个答案:

答案 0 :(得分:4)

将与模板参数无关的数据委托给非模板基类是很常见的,以避免代码重复。在这种情况下,数组的第一个元素的地址不依赖于任何模板参数,因此您可以将其移出

class ContainerBase {
 private: // can't be copied
  ContainerBase(ContainerBase const& o);
  ContainerBase &operator=(ContainerBase &);

 protected:
  ContainerBase(char *datap):datap(datap) { }

 public:
  char *data() { return datap; }

 private:
  char *datap;
};

template<std::size_t size>
class Container : public ContainerBase {
 public:
  Container():ContainerBase(d.characters)
  Container(Container const& o):ContainerBase(d.characters), d(o.d) 
  { }

  Container &operator=(Container const& o) {
    d = o.d;
    return *this;
  }

  struct {
   char characters[size];
  } d;
};


void function(ContainerBase const& input, std::size_t Size){
 /* operate on input.data() */
}

在类似小的类中它可能不会得到回报,但随着独立操作或类本身的增长,成本/使用比率会增加。请注意,如果您的目标是将该类作为聚合,则上述方法不可行。您需要将工作委托给其他非模板化函数,并使用(可能非常小的)生成的模板特化,或者只是手动传递数组的地址。这也有助于使非模板功能更通用

template<std::size_t size>
class Container : public ContainerBase {
 public:
  char *data() { return characters; }

 public:
  char characters[size];
};

// note that this function works in plain arrays too
void function(char *input, std::size_t Size){
 /* operate on input */
}

function(c.data(), N);

顺便说一句,那么你在boost::array<char, N>提供了完全相同的接口和其他有用的功能(仍然是一个聚合),虽然它有点过于笼统,因为它没有在char上修复。

答案 1 :(得分:1)

通常,在需要IN参数的地方,按值传递内置类型,并通过引用const传递其他类型,即

template< size_t size >
void function( Container<size> const& input,size_t Size )
{
 //all instances do exactly same thing and with regard to Size that determines the size of object
}

根据这个定义,编译器+链接器很可能会对事物进行优化,因此只有一个机器代码版本为function

第一次检查一个简单的小例子程序时,我有点惊讶,用编译时多态性(模板)表示它比使用运行时多态性表示更小更高效的代码!

亲自尝试一下,如果你和我曾经一样惊讶,那么好!否则,可能没有显着差异。但是在某些极端情况下,您可能会发现过去被称为“模板代码膨胀”的东西,然后是时候忽略它或者测量它是否足够重要来完成转换为运行时多态性的工作。

现在问你的问题,

  

“我很好奇只有​​一个功能   它接受可变大小   如上所述的参数不是   C ++允许的是不可能的   根本无法实现和生成   装配,或以某种方式导致   就效率而言,效率低下   速度/存储器?“

不,将编译时多态转换为高效的运行时多态,或简单地无多态并非不可能。特别是因为你已经通过了运行时大小(可能保证小于固定大小)。

安全的方法是使用C ++标准库中的std::string标头<string>。这涉及std::string内部的某处动态分配,自动为您完成,但会影响效率。但是你的代码,包含char[size] characters,不是有效的C ++,而且表示初学者级别,所以很可能你的设计没有被选中 - 因此,请执行:

class Container
{
public:
    std::string characters;
};

void function( Container const& input )
{
    // whatever, using e.g. input.characters.length()
}

干杯&amp;第h。,

答案 2 :(得分:1)

一种可能的解决方案是让尺寸模板化的函数将实际工作委托给普通函数,该函数将大小作为普通参数:

#include <cstddef>
#include <cstdio>

template <size_t size>
struct Container
{
    char characters[size];
};

template <size_t size>
inline void function(const Container<size>& input)
{
    real_work(input.characters, size);
}

void real_work(const char* p, size_t len)
{
    while (len--) puts(p++);
}

int main()
{
    Container<6> x = {"hello"};
    function(x);
}

请注意,我故意以不同的方式命名不同类型的参数,以免您感到困惑。

答案 3 :(得分:0)

集装箱&LT 1为卤素;是一个与容器&lt; 2&gt;不同的类型,并且传递指针不会解决任何问题,因为它们将指向不同的类型

你不认为 size 应该是Container的构造函数参数,而不是模板化值吗?

答案 4 :(得分:-1)

无论如何它的设计很糟糕。无论如何,通过值或结构或类传递数组在时间和空间上效率极低,因为必须将整个数组复制到目标堆栈帧中。通过参考。

答案 5 :(得分:-2)

这样的事情对你来说是可以接受的:

class BaseContainer{ /* ... */ };

template<size_t size>
class Container : public BaseContainer{
 public:
  char[size] characters;
};

void function(BaseContainer input,size_t Size){
  //
}