这是我当前拥有的代码:
class Foo
{
public:
template<typename T, typename... Args>
void Function(T t1, Args... args){
// Definition
}
private:
template<typename T>
void Function(T t1){
// Definition
}
};
#include "header.h"
int main()
{
Foo foo;
foo.Function(1, 2, 3, 4, 5);
return 0;
}
工作正常。当我尝试将定义与source.cpp分开时,gcc开始抱怨。我知道我必须专门化模板才能分离定义,所以我尝试将以下代码添加到头文件中:
template<>
void Foo::Function<int, int...>(int t1, int... args);
template<>
void Foo::Function<int>(int);
但没有成功。我想念什么
编辑:gcc错误消息:
header.h:15:28:错误:扩展模式“ int”不包含任何参数 打包void Foo :: Function(int t1,int ... args);
header.h:15:48:错误:扩展模式“ int”不包含任何参数 打包void Foo :: Function(int t1,int ... args);
答案 0 :(得分:2)
您不能将int...
用作参数包,因此这是行不通的。另外,要将源与定义分开,您必须完全指定模板,因此即使允许该语法,int...
也将不起作用。
1。使Function
接受初始化列表。
我们可以编写函数,使其接受int
s的初始化列表:
#include <initializer_list>
class Foo {
public:
void Function(int t1, std::initializer_list<int> t2);
};
void Foo::Function(int t1, std::initializer_list<int> t2) {
for(int i : t2) {
// stuff
}
}
现在,您可以非常轻松地调用Function
,而且它甚至都没有模板化:
Foo f;
f.Function(10, {1, 2, 3, 4, 5});
如果您在其他地方使用模板,则可以将参数包直接扩展到初始化列表中:
template<class... Args>
void invoke_foo(Foo& f, int first, Args... rest) {
f.Function(first, {rest...});
}
2。使用SFINAE禁用所有非int重载。我们可以禁用Foo::Function
的所有重载,这些重载不仅接受int
s
#include <type_traits>
class Foo {
public:
// Requires C++17 for std::conjunction
// You could write your own std::conjunction too if you'd prefer
template<class... Args>
auto Function(int t1, Args... t2)
-> std::enable_if_t<std::conjunction<std::is_same<Args, int>...>::value>
{
// stuff
}
};
不利之处在于,非整数值不会自动转换为int
。
答案 1 :(得分:0)
有更好的方法。
首先,您似乎想强制所有类型的相同参数(这由std::initializer_list
在接受的答案中完成)。可以通过提供额外的显式参数来强制执行此操作:
class Foo
{
public:
template<typename T, typename... Args>
void Function(T t1, T t2, Args... args)
{
LOG;
this->Function(t1);
this->Function(t2, args...);
}
private:
template<typename T>
void Function(T t1)
{
LOG << VAR(t1);
}
};
template<>
void Foo::Function<int>(int x)
{
LOG << " Spec" << VAR(x);
}
如您所见,如果为单个参数提供方法的特殊化就足够了。