Вопрос:
Если, например, вам нужна переменная функция, которая принимает произвольное число параметров Args&&...args
и печатает все эти аргументы t
раз. Более того, вы хотите, чтобы значение t
по умолчанию было 1
, поэтому по умолчанию он печатает все args
один раз.
Первое, что вы попробуете:
template <typename ... Args>
void foo(Args... args, unsigned t = 1) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
Очевидно, что это не сработает, если вы не передадите явно параметры шаблона:
// Error: expected 1 argument, got 2
foo(0, "Hello, world!");
Поскольку параметры по умолчанию обрабатываются как обычные параметры при вычитании шаблона, а пакет параметров всегда будет пустым. Это мешает вам сделать функцию полезной. ( Смежный вопрос )
Затем я решил использовать агрегатную инициализацию (особенно обозначенный инициализатор начиная с c ++ 20) для имитации более мощного «параметра по умолчанию». Выглядит это так:
struct foo_t {
unsigned t = 1;
template <typename ... Args>
void operator() (Args... args) {
for (unsigned i = 0; i < t; ++i) {
(std::cout << ... << args);
}
}
};
int main() {
foo_t{}("Hello, ", "World!\n"); // prints 1 line
foo_t{ 5 }(0, "Hello, world!\n"); // prints 5 lines
return 0;
}
Более того, это может разрешить жалобу людей на то, что они не могут «пропустить» параметры функции по умолчанию с помощью с ++ 20 обозначенных инициализаторов:
struct bar_t {
const std::string& str = "Hello, world!";
int t = 1;
void operator() () {
for (int i = 0; i < t; ++i) {
std::cout << str << std::endl;
}
}
};
int main() {
// Skips .str, using the default "Hello, World!"
bar_t{ .t = 10 }();
return 0;
}
Мне интересно, есть ли какие-нибудь потенциальные ловушки, чтобы сделать это.
Справочная информация (может быть безопасно проигнорировано)
Итак, вчера я бродил по SO и столкнулся с вопросом (нопозже он был удален), который спрашивал о том, как объединить параметр std::source_location
по умолчанию с шаблоном переменной:
template<typename... Args>
void log(Args&&... args, const std::experimental::source_location& location = std::experimental::source_location::current()) {
std::cout << location.line() << std::endl;
}
Очевидно, что это работает не так, как ожидалось, как указано в вопросе. Итак, я придумал следующий код:
struct logger {
const std::experimental::source_location& location = std::experimental::source_location::current();
template <typename... Args>
void operator() (Args&&... args) {
std::cout << location.line() << std::endl;
}
};
int main(int argc, char** argv) {
logger{}("I passed", argc, "arguments.");
return 0;
}
Но обнаружил, что он может сделать больше, таким образом, этот вопрос.