比方说,我有类似的东西
#include <iostream>
template <class Arg>
void helper(Arg&& arg) {
// do something with the type and value
}
void vt(){}
template <class Arg, class... Args>
void vt(Arg&& arg, Args&&... rest) {
helper(arg);
vt(rest...);
}
int main() {
vt(1, 1.1, "abc");
}
现在,我的问题是,如何在cpp文件中包装vt()
之类的可变参数模板函数。基本上,我想对我的库中的客户端隐藏实现。
我考虑过使用va_list
,但是它很慢,更重要的是,为了遍历列表,我需要提前知道类型,这是不可能的,因为我不知道调用者可能会做什么传递(除了变量参数必须是原始C类型)。
如果解决方案需要GCC专用的东西,我也可以。
如果解决方案必须删除可变参数模板,则可以解决,只要解决方案可以迭代可变参数,获取每个参数的类型(helper()
需要信息)并获取每个参数的值即可。
谢谢!
答案 0 :(得分:1)
有一个解决方案,但是它涉及typeinfo
,可能会对性能产生影响。
#include <iostream>
#include <typeinfo>
#include <cstdarg>
using namespace std;
// This is the function you could puts its implementation in a separate file
// Use only its prototype in the header
void funcWithValist(int count, ...) {
va_list a;
va_start(a, count);
for(int i=0;i<count;i++) {
// Here is an example to extract the type info (you can use anything
// instead of name() )
cout << va_arg(a, std::type_info *)->name() << "\n";
}
}
// The C++ wrapper function, this is to be put in the header file
template<typename... T>
void funcWithArgs(const T&... t) {
funcWithValist(sizeof...(t), (&typeid(t))..., t...);
// Expanded into: the number of args, &typeid(arg1), &typeid(arg2), ...
// arg1, arg2, ...
}
int main() {
// Example of the call
funcWithArgs(4, std::string("Aaa"));
return 0;
}
答案 1 :(得分:1)
问题是模板必须在标头中是有充分理由的。换句话说,并不是某些神秘的语言规则如此决定。
这样做的原因是模板功能是不是功能。它们是模板,使您能够生成函数。为此,用户代码必须能够看到整个模板定义。
请注意,如果您不需要模板使用每种可能的类型和任何可能的工具,您都可以这样做,但我建议这样做。
#include<algorithm>
#include<vector>
#include<iostream>
#include<variant>
using my_v=std::variant<std::monostate, int, double, const char*>;
void func(const my_v& a1= std::monostate{}, const my_v& a2 = std::monostate{},
const my_v& a3 = std::monostate{} );
struct visitor{
void operator()(const my_v& v) const{
if (std::holds_alternative<int>(v)){
std::cout << "got int: " << std::get<int>(v) << std::endl;
}
if (std::holds_alternative<const char*>(v)){
std::cout << "got string: " << std::get<const char*>(v) << std::endl;
}
if (std::holds_alternative<double>(v)){
std::cout << "got double: " << std::get<double>(v) << std::endl;
}
if (std::holds_alternative<std::monostate>(v)){
// empty function argument
}
}
};
void func(const my_v& a1, const my_v& a2, const my_v& a3){
std::visit(visitor{}, a1);
std::visit(visitor{}, a2);
std::visit(visitor{}, a3);
}
int main()
{
func(double{42}, "hello");
}