对于C++模板,编译器必须在编译时产生每个实例。因此,对于每个参数组合(int,double,float)
,相应的实例应该出现在目标文件中。
您的foo
不可能知道每个参数组合,因为有无限量 - 所以除非您以某种方式限制参数空间,否则您的问题的答案是“否”。
然而,一些模板魔术也可能,但没有实际用途。我举一个具体的例子作为概念验证,但请不要在实际代码中使用它。
比方说
void foo(const char* s, ...);
期望格式字符串等"ffis"
,其中每个字符指定(在这种情况下双,双,整数,字符串)参数类型。我们也有一个可变参数模板bar
功能,打印它的参数:
template <typename Arg, typename... Args>
void doPrint(std::ostream& out, Arg&& arg, Args&&... args)
{
out << std::forward<Arg>(arg);
using expander = int[];
(void)expander {
0, (void(out << ", " << std::forward<Args>(args)), 0)...
};
out << '\n';
}
void bar() {
std::cout << "no arguments\n";
}
template<typename... Args>
void bar(Args... arguments) {
doPrint(std::cout, arguments...);
}
对于foo
工作,我们将在编译时产生每一个可能的参数组合的最大长度是N
(所以,3^N情况下):
//struct required to specialize on N=0 case
template<int N>
struct CallFoo {
template<typename... Args>
static void foo1(const char* fmt, va_list args, Args... arguments) {
if (*fmt) {
using CallFooNext = CallFoo<N - 1>;
switch (*fmt) {
case 'f':
{
double t = va_arg(args, double);
CallFooNext::foo1(fmt + 1, args, arguments..., t);
}break;
case 'i':
{
int t = va_arg(args, int);
CallFooNext::foo1(fmt + 1, args, arguments..., t);
}break;
case 's':
{
const char* t = va_arg(args, const char*);
CallFooNext::foo1(fmt + 1, args, arguments..., t);
}break;
}
} else {
bar(arguments...);
}
}
};
template<>
struct CallFoo<0> {
template<typename... Args>
static void foo1(const char* fmt, va_list args, Args... arguments) {
bar(arguments...);
}
};
void foo(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
//Here we set N = 6
CallFoo<6>::foo1<>(fmt, args);
va_end(args);
}
主要功能,为了完整性:
int main() {
foo("ffis", 2.3, 3.4, 1, "hello!");
}
所得的代码编译约10秒机智h gcc
,但生成正确的字符串2.3, 3.4, 1, hello!
不,这是不可能的。 –
这将如何使它成为任何救星?一旦变量处于'...'中,每个类型信息都会丢失,这正是使其不可用的原因。这种损失是无法收回的。请注意,当然,您可以明确地将'va_list'的内容转换为某些类型,然后由variadic模板将其拾取,但是没有任何内容会自动为您恢复丢失的类型信息。 –