У вас есть пара проблем. Для выпуска времени компиляции:
if (std::is_same<Head, uint8_t>::value)
к этому:
if constexpr (std::is_same<Head, uint8_t>::value)
Это потому, что вы хотите скомпилировать тело if только тогда, когда допустимо приведение к uint. То, что время выполнения if равно false, не означает, что код внутри него не должен быть действительным. Constexpr, если решит это.
Далее, ваше сравнение типов слишком строго. Сравнение ссылки с не-ссылкой вернет false. Итак, вы хотите убрать тип перед тестом is_same. Я также предпочитаю is_same_v здесь:
if constexpr (std::is_same_v<std::decay_t<Head>, uint8_t>)
Наконец, ваш базовый случай, последний элемент, все еще нуждается в том же типе «if constexpr», чтобы правильно его печатать, но вы применили эту логику только в основном цикле.
Собираем это вместе:
template<class Head>
void print_args(std::ostream& s, Head&& head) {
if constexpr (std::is_same_v<std::decay_t<Head>, uint8_t>)
s << static_cast<int>(head);
else
s << head << ",";}
template<class Head, class... Tail>
void print_args(std::ostream& s, Head&& head, Tail&&... tail) {
if constexpr (std::is_same_v<std::decay_t<Head>, uint8_t>)
s << static_cast<int>(head) << ",";
else
s << head << ",";
print_args(s, std::forward<Tail>(tail)...);
}
template<class... Args>
void print_args(Args&&... args) {
print_args(std::cout, std::forward<Args>(args)...);
}
Вы можете выделить общее число, если constexpr, в одну вспомогательную функцию, чтобы уменьшить избыточный код и сохранить его СУХИМЫМ. Но вместо того, чтобы идти туда, я предложу кое-что еще.
Просто заставить его работать не всегда лучшая цель. Рекурсивные шаблоны могут использовать больше памяти в компиляторе и замедлять сборки, поэтому решения, которые избегают рекурсии, лучше, если они дают одинаковые результаты.
В качестве такового рассмотрим выражение сгиба (c ++ 17) и лямбду для вывода кода:
Все вышеперечисленное можно заменить на это :
template<class... Args>
void print_args(Args&&... args) {
([](auto&& arg)
{
if constexpr (std::is_same_v<std::decay_t<decltype(arg)>, uint8_t>)
std::cout << static_cast<int>(std::forward<Args>(arg));
else
std::cout << arg;
if (sizeof...(Args) > 1)
std::cout << ",";
}(args), ...);
}
Разбивая его, он использует выражение сгиба для оператора запятой, используя IILE (Лямбда-выражение с немедленным вызовом) в форме (f (x) op ...), где f (x) - лямбда (учитывая current arg), а «op» является оператором запятой для последовательности вызовов.) Второе «if» предотвращает конечную запятую.