可变参数模板和新的

发布于 2024-12-05 05:38:43 字数 761 浏览 0 评论 0原文

我有这样的类模板:

template<class... T>
class Test {
  std::vector<TestCase*> test_cases;
public:
  Test() {
    // Here, for each T an instance should be added to test_cases.
    test_cases.push_back((new T)...);
  }
};

这对于一个模板参数来说效果很好,但是对于多个参数我收到此错误:

error: too many arguments to function call, expected 1, have 2

如何以这种方式将可变参数模板与 new 一起使用?正确的语法是什么?


编辑:我认为我的问题不太清楚。我想要的是这样的:

Test<TestCase1, TestCase2, TestCase3>;
// The constructor will then be:
test_cases.push_back(new TestCase1);
test_cases.push_back(new TestCase2);
test_cases.push_back(new TestCase3);

我的编译器是 clang 163.7.1,带有此标志:-std=c++0x

I have this class template:

template<class... T>
class Test {
  std::vector<TestCase*> test_cases;
public:
  Test() {
    // Here, for each T an instance should be added to test_cases.
    test_cases.push_back((new T)...);
  }
};

This works fine for one template argument, but for multiple arguments I get this error:

error: too many arguments to function call, expected 1, have 2

How can I use variadic templates with new this way? What is the correct syntax?


EDIT: I think my question wasn't quite clear. What I want is this:

Test<TestCase1, TestCase2, TestCase3>;
// The constructor will then be:
test_cases.push_back(new TestCase1);
test_cases.push_back(new TestCase2);
test_cases.push_back(new TestCase3);

My compiler is clang 163.7.1 with this flag: -std=c++0x.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

英雄似剑 2024-12-12 05:38:43

vector::push_back 需要一个参数,因此您无法在函数调用中扩展可变参数模板。
我还为基类(所有其他类派生自该基类)添加了一个模板参数。

这是编译的内容

struct base{};
struct d0 : base{};
struct d1 : base{};
struct d2 : base{};

#include <vector>

// termination condition for helper function
template <class T>
void add(std::vector<T*>&) { 
}

// helper function
template <class T, class Head, class... Tail>
void add(std::vector<T*>& v) { 
       v.push_back(new Head()); 
       add<T, Tail...>(v);
}

template <class T, class ... U>
class test
{
    std::vector<T*> vec;
public:
    test() {
       add<T, U...>(vec);      
    }
};

int main() 
{
    test<base, d0,d1,d2> t;
}

vector::push_back expects one parameter so you can't expand the variadic template in the function call.
Also I added a template parameter for the base class (from which all other classes derive).

Here's something that compiles.

struct base{};
struct d0 : base{};
struct d1 : base{};
struct d2 : base{};

#include <vector>

// termination condition for helper function
template <class T>
void add(std::vector<T*>&) { 
}

// helper function
template <class T, class Head, class... Tail>
void add(std::vector<T*>& v) { 
       v.push_back(new Head()); 
       add<T, Tail...>(v);
}

template <class T, class ... U>
class test
{
    std::vector<T*> vec;
public:
    test() {
       add<T, U...>(vec);      
    }
};

int main() 
{
    test<base, d0,d1,d2> t;
}
蒗幽 2024-12-12 05:38:43

可以完成此任务,但由于您直接编写表达式,因此有点迂回。您需要为可变参数模板参数列表中的每个参数调用一次push_back

你如何实现这一目标?好吧,通过为每个模板参数调用一次递归函数:

template <typename Base, typename T1, typename T2, typename... T>
void fill(std::vector<Base*>& vec) {
    vec.push_back(new T1);
    fill<Base, T2, T...>(vec);
}

template <typename Base, typename T1>
void fill(std::vector<Base*>& vec) {
    vec.push_back(new T1);
}

这里我们有两个 fill 函数的重载,一个带有可变参数模板参数列表,另一个没有 - 这是递归基本情况。只要仍然至少有两个模板参数,就会调用第一个版本。如果只剩下一个参数,则调用第二个参数。

在构造函数中这样调用它:

fill<TestCase, T...>(test_cases);

You can accomplish this, but it’s a bit roundabout since you write the expression directly. You need to call push_back once for each argument in the variadic template argument list.

How do you achieve this? Well, by calling a recursive function once for each template argument:

template <typename Base, typename T1, typename T2, typename... T>
void fill(std::vector<Base*>& vec) {
    vec.push_back(new T1);
    fill<Base, T2, T...>(vec);
}

template <typename Base, typename T1>
void fill(std::vector<Base*>& vec) {
    vec.push_back(new T1);
}

Here we have two overloads of the fill function, one with a variadic template argument list and one without – this is the recursion base case. As long as there are still at least two template arguments, the first version gets called. If there is only a single argument left, the second argument is called instead.

Call it like this in the constructor:

fill<TestCase, T...>(test_cases);
阳光的暖冬 2024-12-12 05:38:43

包扩展只能在选定的几种情况下发生,并且不适用于任意表达式或语句。但是,由于其中一种情况是列表初始化,并且由于操作顺序是为列表初始化语法的大括号初始值设定项定义的,因此始终可以扩展任意语句。也就是说:

typedef std::initializer_list<int> expand;
expand { ( test_cases.push_back(new T), void(), 0 )... };

void() 技巧是抑制对重载运算符 的任何调用。此处完全不相关,但我已将其包含在内,因为在重构宏中的功能时它可能很有用:

#define EXPAND( exp ) \
    std::initializer_list<int> { ( (exp), void(), 0 )... }

// No use of '...', it's in the macro body
EXPAND(( test_cases.push_back(new T) ));

Pack expansion can only happen in a select number of situations and doesn't work for arbitrary expressions or statements. However, since one of those situation is list-initialization and since the order of operations is defined for the brace initializers of list-initialization syntax, it's always possible to expand an arbitrary statement. To wit:

typedef std::initializer_list<int> expand;
expand { ( test_cases.push_back(new T), void(), 0 )... };

The void() trick is to suppress any invocation of an overloaded operator,. Completely irrelevant here but I have included it since it may be useful when refactoring the functionality in a macro:

#define EXPAND( exp ) \
    std::initializer_list<int> { ( (exp), void(), 0 )... }

// No use of '...', it's in the macro body
EXPAND(( test_cases.push_back(new T) ));
知你几分 2024-12-12 05:38:43

相关说明,在这种特殊情况下,您可以通过如下编写构造函数来使用向量的 initializer_list 支持,

Test()
:test_cases{ new T ... }
{ }

或者如果由于任何原因无法使用构造函数初始值设定项,则可以使用赋值

Test() {
  test_cases = { new T ... };
}

On a related note, in this particular case you can use vector's initializer_list support by writing the constructor as follows

Test()
:test_cases{ new T ... }
{ }

Or by using assignment if for any reason you can't use constructor initializers

Test() {
  test_cases = { new T ... };
}
锦上情书 2024-12-12 05:38:43

也许您想要 std::vector 中的元组?不确定这是否是您想要的,但这至少可以在我的 G++ 4.6.1 上编译:D

#include <vector>
#include <utility>
#include <functional>
#include <string>

template<class... T>
class Test {
  std::vector<std::tuple<T*...>> test_cases;
public:
  Test() {
    // Here, for each T an instance should be added to test_cases.
    test_cases.push_back(std::tuple<T*...>((new T)...));
  }
};

int main()
{
   Test<int, float> foo;
   Test<std::string, double> bar;
}

Maybe you want a tuple inside your std::vector? Not sure if this is what you intended, but this compiles at least on my G++ 4.6.1 :D

#include <vector>
#include <utility>
#include <functional>
#include <string>

template<class... T>
class Test {
  std::vector<std::tuple<T*...>> test_cases;
public:
  Test() {
    // Here, for each T an instance should be added to test_cases.
    test_cases.push_back(std::tuple<T*...>((new T)...));
  }
};

int main()
{
   Test<int, float> foo;
   Test<std::string, double> bar;
}
淡看悲欢离合 2024-12-12 05:38:43

我突然想到你想要一个 any 类型的动态向量(虽然不是我个人看的,但一位朋友告诉我,boost 库中显然有类似的东西),而不是模板向量。

模板向量基本上是一个可以采用任何一个定义类型的向量(所有整数,或所有双精度数,或所有浮点数,但不是整数、双精度数和浮点数)。

传统上没有这样的类的原因是因为每个项目在内存中占用不同的块大小(char 是一个字节,int 可以是 4 个字节等),并且在查找时需要额外的资源知道会发生什么(正常存储是连续的......向量是什么,假设它“基本上”是一个数组)。

如果你想构建自己的(我尝试过),你会看到 void * 指针、动态内存分配和涉及类型转换的一系列令人头疼的问题(我不知道有任何自动化方法可以在幕后正确类型转换项目) ,但其他人也许能够参与)。

It strikes me you want a dynamic vector of any type (although not personally looking myself, I was told by a friend there was apparently something like this in the boost library), as opposed to a template vector.

A template vector is basically a vector that can assume any of one defined type (either all ints, or all doubles, or all floats but not ints and doubles and floats).

The reason there isn't a class like this conventionally is because each item takes up a different block size in memory (a char is a byte, an int could be 4 bytes etc etc), and it would take additional resources on look-up to know what to expect (normal storage is contiguous... which a vector is, given it is 'basically' an array).

If you're looking to build your own (I tried), you're looking at void * pointers, dynamic memory allocation and a whole host of headaches involving typecasting (I am unaware of any automated method to correctly typecast an item behind the scenes, but others might be able to chip in).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文