Итак, я использую простой пример, чтобы попытаться понять шаблоны с переменным числом аргументов и некоторые приемы tmp. Пример состоит из класса Timer, у которого есть метод toc (). Методы toc используются для остановки таймера и вызова функции, которая решает, что делать (распечатать, сохранить в переменной ...)
Итак, я закодировал эту идею следующим образом (я убрал биты синхронизации)
class VerbosePolicy {
public:
VerbosePolicy() {}
explicit VerbosePolicy(const std::string &message) : m_message(message) {}
VerbosePolicy(VerbosePolicy &&other) { m_message = other.m_message; }
void operator()(double time) { std::cout << m_message << time << std::endl; }
private:
std::string m_message;
};
template <typename Policy, typename... Args> class Timer {
public:
Timer(Args... args) : m_policy(Policy(std::forward<Args>(args)...)) {}
void toc(double time) { m_policy(time); }
private:
Policy m_policy;
};
Здесь я создаю Таймер с Политикой и вызываю ctor Полиса с пакетом параметров. Таким образом, я могу контролировать работу Политики (например, я могу передать переменную и сохранить там результат).
Теперь я хочу использовать это
int main(int argc, char **argv) {
std::string string = "Elapsed time";
Timer<VerbosePolicy> timer(string);
timer.toc(1.0);
}
Проблема здесь в том, что компилятор не может определить, является ли строка частью пакета параметров, и пытается сопоставить ее со временем политики, что не удается.
Я попытался добавить аргумент по умолчанию для таймера ctor
Timer(Args... args, Policy policy = Policy())
Но это также не удается, так как он все еще пытается сопоставить de string с типом политики (в этом случае он пытается вызвать второй ctor, который завершается ошибкой, поскольку он помечен как явный. Если я удаляю его, он компилируется, но работает неправильно, потому что значение политики его неверно).
Все отлично работает, если я пишу
Timer<VerbosePolicy, std::string> timer(string)
, поскольку больше не нужно выводить шаблон переменной.
В любом случае, я могу избежать написания std :: string?
Спасибо!
EDIT:
Для полноты и решения некоторых проблем, о которых говорилось в комментариях к действительному ответу, я пытался деактивировать конструктор переменных, когда параметр такого же типа, как и таймер, без успеха.
Мой подход был
template <typename T, typename... Tail> struct first_of { using type = T; };
template <typename Policy> class Timer {
public:
template <
typename... CArgs,
std::enable_if_t<!std::is_same<Timer<Policy>,
typename first_of<CArgs...>::type>::value,
int> = 0>
Timer(CArgs &&... args) : m_policy(std::forward<CArgs>(args)...) {}
Timer(const Timer<Policy> &other) : m_policy(other.m_policy) {}
void toc(double time) { m_policy(time); }
private:
Policy m_policy;
};
int main(int argc, char **argv) {
std::string string = "Elapsed time";
Timer<VerbosePolicy> timer(string);
Timer<VerbosePolicy> timer2(timer);
timer.toc(1.0);
}
Но компилятор все еще пытается использовать конструктор variadic для timer2. Я не уверен, почему он пытается это сделать, поскольку два типа, передаваемые в std :: is_same, должны быть равны, и поэтому ctor должен быть деактивирован.
Что я недопонимаю?
Еще раз спасибо!