C++ 模板中的多个类型名参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19923353/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple typename arguments in c++ template?
提问by Jichao
How can I have multiple typename arguments in a c++ template?
如何在 C++ 模板中有多个 typename 参数?
#ifndef _CALL_TEMP_H
#define _CALL_TEMP_H
#include <string>
#include <iostream>
template <typename Sig>
class Foo;
template <typename A, typename B>
class Foo
{
public:
void output() {
std::cout << a_ << b_ << std::endl;
}
A a_;
B b_;
};
template <typename A, typename B, typename C>
class Foo
{
public:
void output() {
std::cout << a_ << b_ << c_ << std::endl;
}
A a_;
B b_;
C c_;
};
#endif
Usage:
用法:
int main()
{
Foo<int ,int> doubleint;
doubleint.a_ = 1;
doubleint.b_ = 2;
doubleint.output();
// Foo<int , int , std::string> comp;
// comp.a_ = 1;
// comp.b_ = 2;
// comp.c_ = "haha";
// comp.output();
return 0;
}
But it will not compile. How could I make it compile?
但它不会编译。我怎样才能让它编译?
回答by Dietmar Kühl
Just declare a primary template with a variadic template and then specialize for each supported number of template arguments. For example:
只需使用可变参数模板声明一个主模板,然后专门针对每个支持数量的模板参数。例如:
#ifndef CALL_TEMP_H
#define CALL_TEMP_H
#include <iostream>
template <typename...> class Foo;
template <typename A, typename B>
class Foo<A, B>
{
public:
void output() {
std::cout << a_ << b_ << '\n';
}
A a_;
B b_;
};
template <typename A, typename B, typename C>
class Foo<A, B, C>
{
public:
void output() {
std::cout << a_ << b_ << c_ << '\n';
}
A a_;
B b_;
C c_;
};
#endif
I you can't use C++11 and you want to retain a similar notation you'll need to simulate a variadic argument list with template default arguments. This will implicitly limit the number of templare arguments but since you are specializing the templates anyway, this limitation doesn't realky matter.
我你不能使用 C++11 并且你想保留一个类似的符号,你需要用模板默认参数模拟可变参数列表。这将隐式限制 templare 参数的数量,但由于您无论如何都在专门化模板,因此此限制并不重要。
If it is acceptable to use a different notation you can also use something which looks like a function declaration to instantiate and specialize your template:
如果可以使用不同的符号,您还可以使用类似于函数声明的东西来实例化和专门化您的模板:
template <typename> class Foo;
template <typename A, typename B>
class Foo<void(A, B)> {
...
};
template <typename A, typename B, typename C>
class Foo<void(A, B, C)> {
...
};
...
Foo<void(int, int)> f2;
Foo<void(int, int, std::string)> f3;
Whether the change in notation is acceptable depends on your use of the class template. You won't achieve an ideal solution as with variadic templates without C++11, though.
符号的更改是否可以接受取决于您对类模板的使用。但是,如果没有 C++11,您将无法像使用可变参数模板那样获得理想的解决方案。
BTW, don't overuse std::endl
: use '\n'
to mean end of line. If you really mean to flush the stream, use std::flush
. Also _CALL_TEMP_H
is a name reserved to the standard C++ library as are all names starting with an underscore followed by a capital character: do notuse these names in your own code unless there is explicit permission to use them (e.g. __FILE__
and __LINE__
are reserved but explicit permission to use them is granted).
顺便说一句,不要过度使用std::endl
:用于'\n'
表示行尾。如果您真的想刷新流,请使用std::flush
. 也是_CALL_TEMP_H
标准 C++ 库保留的名称,所有以下划线开头后跟大写字符的名称也是如此:除非有明确的使用许可,否则不要在您自己的代码中使用这些名称(例如__FILE__
,__LINE__
保留但明确许可使用它们是被授予的)。
回答by Kaz Dragon
If you have multiple versions of a template, you have to specialize a single version. If you want a different number of arguments, then the trick is to use a tag class to say "this argument is no argument", and have that as a default argument.
如果您有多个版本的模板,则必须专门化一个版本。如果你想要不同数量的参数,那么诀窍是使用标签类来说明“这个参数没有参数”,并将其作为默认参数。
In your case, something like the following works (compiled and tested):
在您的情况下,类似以下的工作(编译和测试):
#include <iostream>
// tag class indicating "no member in this place"
struct nothing {};
template <typename A, typename B, typename C = nothing> // <- note default arg.
class Foo;
template <typename A, typename B>
class Foo<A, B, nothing> // <- note specialization
{
public :
void output() {
std::cout << a_ << b_ << std::endl;
}
A a_;
B b_;
};
template <typename A, typename B, typename C>
class Foo
{
public :
void output() {
std::cout << a_ << b_ << c_ << std::endl;
}
A a_;
B b_;
C c_;
};
int main()
{
Foo<int, int> doubleint;
doubleint.a_ = 1;
doubleint.b_ = 2;
doubleint.output();
Foo<int, int, int> tripleint;
tripleint.a_ = 1;
tripleint.b_ = 2;
tripleint.c_ = 3;
tripleint.output();
}
Note that this is essentially a re-invention of boost::tuple<>/std::tuple<>, which you should definitely read up on.
请注意,这本质上是对 boost::tuple<>/std::tuple<> 的重新发明,您绝对应该仔细阅读。
回答by legends2k
I think you're confusing specialization with overloading the same class name. You cannot create a class with the same name with multiple template arguments.
我认为您将专业化与重载相同的类名混淆了。您不能创建具有多个模板参数的同名类。
回答by Tristan Brindle
It won't compile because you can't have the same class defined multiple times with a different number of template arguments.
它不会编译,因为您不能使用不同数量的模板参数多次定义同一个类。
If you know the maximum number of template parameters you want to support, you could use partial specialisation:
如果您知道要支持的模板参数的最大数量,则可以使用部分专业化:
// main template
template <typename A, typename B = void, typename C = void>
struct Foo
{
void output() { std::cout << a_ << b_ << c_ << std::endl; }
A a_;
B b_;
C c_;
};
// Partial specialisation for two parameters
template <typename A, typename B>
struct Foo<A, B, void>
{
void output() { std::cout << a_ << b_ << c_ << std::endl; }
A a_;
B B_;
};
// Partial specialisation for one parameter
template <typename A>
struct Foo<A, void, void>
{
void output() { std::cout << a_ << std::endl; }
A a_;
};
If you're using C++11, another option would be to use variadic templates.
如果您使用的是 C++11,另一种选择是使用可变参数模板。