Для шаблона C++ компилятор должен производить каждый экземпляр во время компиляции. Таким образом, для каждой комбинации параметров (int,double,float)
соответствующий экземпляр должен отображаться в объектном файле.
Невозможно узнать каждую комбинацию параметров, так как есть бесконечное количество - поэтому, если вы каким-либо образом не ограничиваете пространство параметров, ответ на ваш вопрос «нет».
Однако, с некоторым шаблоном магии это возможно, но практически не полезно. Я показываю один конкретный пример как доказательство концепции, но, пожалуйста, не используйте это в реальном коде.
Позволяет сказать
void foo(const char* s, ...);
ожидает строку формата, как "ffis"
, где каждый символ указывает тип параметра (двойной, двойной, целое число, строка в данном случае). Мы также VARIADIC функции шаблона 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' для некоторых типов, которые затем будут подбираться вариативными шаблонами, но ничто не будет автоматически восстанавливать информацию о потерянном типе. –