Шаблоны Variadic имеют много преимуществ, но есть ли случаи, когда вместо этого следует использовать вариативные функции C-стиля (используя <cstdarg>
)?Есть ли случай, когда функции vararg предпочтительнее, чем вариативные шаблоны?
ответ
Если вы предоставляете C API с реализацией C++, тогда шаблоны не являются опцией для API. Варгары есть.
Если вам необходимо поддерживать компилятор, который не поддерживает стандарт C++ 11 или более новый, то вариативные шаблоны недоступны. Варгары есть.
Если вам нужен компиляторный брандмауэр. То есть вам нужно скрыть реализацию функции из заголовка, тогда вариационный шаблон не является вариантом. Варгары есть.
В системах с ограниченной памятью (вложенных) различные функции, генерируемые шаблоном, могут вводить слишком много раздувания. Тем не менее, такие системы обычно также являются реальным временем, и в этом случае varargs также может быть неприемлемым из-за разветвления и использования стека.
Я хочу добавить к excellent answer of @user2079303
также спискам параметров используется в некотором метапрограммировании (черт реализованное с SFINAE, например) из-за их имущество рассматривается последними на перегруженном.
Допустим, мы хотим реализовать черту, чтобы обнаружить, если класс конструктивна от некоторых типов (что-то вроде std::is_constructible:
Упрощенная современная реализация будет идти, как это (это не единственный способ: как было указано, void_t
может также be used to implement the trait и в ближайшее время (? 2020) мы не будем нуждаться в какой-либо из этих уловок, как concepts находятся на пути с пунктом require
в качестве первого класса гражданина):
template <class T, class... Args> struct Is_constructible {
template <class... Params>
static auto test(Params... params) -> decltype(T{params...}, std::true_type{});
static auto test(...) -> std::false_type;
static constexpr bool value = decltype(test(std::declval<Args>()...))::value;
};
Это работает из-за SFINAE: когда instantiati ng test
, если семантика недействительна из-за некоторого dependent name, тогда это не является жесткой ошибкой, вместо этого перегрузка просто игнорируется.
Если вы хотите узнать больше о трюках-чертах и о том, как они реализованы и как они работают, вы можете прочитать далее: sfinae idiom, member detector idiom, enable_if idiom.
Итак, с типом X
, который может быть построен только из 2 Интс:
struct X { X(int, int) {}; };
мы получаем следующие результаты:
Is_constructible<X, int, int>::value // true
Is_constructible<X, int>::value; // false
Вопрос теперь заключается в том, можно ли заменить тест списков параметров с вариационные шаблоны:
template <class T, class... Args> struct Is_constructible_broken {
template <class... Params>
static auto test(Params... params) -> decltype(T{params...}, std::true_type{});
template <class... Params>
static auto test(Params...) -> std::false_type;
static constexpr bool value = decltype(test(std::declval<Args>()...))::value;
};
И ответ нет (по крайней мере, нет t - прямая замена).Когда мы создаем
Is_constructible_broken<X, int, int>::value
мы получаем ошибку:
error: call of overloaded '
test(int, int)
' is ambiguous
, потому что оба перегруженных являются жизнеспособными, и оба имеют один и тот же «ранга» в разрешении перегрузки. Первая реализация с varargs работает, потому что, даже если обе перегрузки жизнеспособны, вариационный шаблон является предпочтительным по сравнению с vararg.
Оказывается, вы можете заставить его работать с вариативными шаблонами. Хитрость заключается в том, чтобы добавить искусственный параметр test
, что это идеально подходит для первой перегрузки и преобразования для второго:
struct overload_low_priority{};
struct overload_high_priority : overload_low_priority {};
template <class T, class... Args> struct Is_constructible2 {
template <class... Params>
static auto test(overload_high_priority, Params... params)
-> decltype(T{params...}, std::true_type{});
template <class... Params>
static auto test(overload_low_priority, Params...) -> std::false_type;
static constexpr bool value
= decltype(test(overload_high_priority{}, std::declval<Args>()...))::value;
};
Но я думаю, что переменные аргументы более ясно в этом случае.
Обратите внимание, что 'void_t' может использоваться для создания признаков вместо использования многоточия. – Jarod42
@ Jarod42 да, и скоро это тоже будет устаревшим с помощью [require clause] (http://en.cppreference.com/w/cpp/language/constraints) – bolov
Я предпочитаю 'struct high_overload_priority: low_overload_priority {};' использование над 'int' /' long', чтобы заказать перегрузку. – Jarod42
vararg позволяет использовать __attribute__ format
. Например.
void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void f(float value)
{
debug("value = %d\n", value); // <- will show warning.
}
К сожалению, этого не может быть достигнуто с использованием вариативных шаблонов.
Отредактировано:Как отметил Владимир, я забыл упомянуть, что __attribute__ format
не является частью стандарта, однако он поддерживается как GCC, так и Clang (но не Visual Studio). Для получения дополнительной информации см.: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
Я бы посоветовал вам поставить ссылку на использование формата __attribute__, поскольку он не является стандартным. Я также думаю, что хорошо показать некоторые из компиляторов, которые он использует. Я знаю только GCC. –
https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html –
- 1. Есть ли способ вручную расширить вариативные шаблоны?
- 2. Имитировать вариативные шаблоны в C#
- 3. Как скомпилировать вариативные шаблоны условно?
- 4. Как использовать вариативные шаблоны для обертывания переменных аргументов функции?
- 5. Есть ли случай, когда '&' дает более низкую производительность, чем '%'?
- 6. Когда сортировка слияния предпочтительнее, чем Quick sort?
- 7. Есть ли какой-нибудь случай, когда вместо файла css предпочтительнее <style>?
- 8. Есть ли случай, когда синтаксис делегата предпочтительнее выражения лямбда для анонимных методов?
- 9. Есть ли какой-либо конкретный случай, когда значение pass-by-value предпочтительнее, чем pass-by-const-reference в C++?
- 10. Есть ли случай, когда self.location! = Document.location?
- 11. другое решение, чем случай, когда
- 12. Is/**/комментарий предпочтительнее, чем //?
- 13. Есть ли альтернатива C# для Java vararg?
- 14. Пул потоков - обрабатывайте случай, когда есть больше задач, чем потоки
- 15. Ошибка компилятора при передаче ссылки rvalue через вариативные шаблоны
- 16. Когда abort() предпочтительнее выхода()?
- 17. использовать «случай когда» после функции
- 18. Есть ли случай, когда ячейка таблицы будет игнорировать минимальную ширину?
- 19. Есть ли отладочные шаблоны?
- 20. есть ли случай, когда переменной можно присвоить функцию void?
- 21. Есть ли случай, когда проверка параметров может считаться избыточной?
- 22. Есть ли случай, когда "[^ xy]" не равно "(?! X | y)."?
- 23. C++ Шаблоны: встроены ли шаблоны? Есть ли недостатки в производительности?
- 24. вызов функции vararg с массивом?
- 25. Clojure Spec для функции vararg
- 26. Visual Studio 2012 Update 3 - список инициализаторов и вариативные шаблоны
- 27. В любом случае, когда очередь предпочтительнее, чем круговая очередь?
- 28. Шаблонные параметры шаблона и вариативные шаблоны с gcc 4.4
- 29. Вложенные вариативные шаблоны: ошибка в gcc или clang?
- 30. Как я объявляю std :: tuple, используя вариативные шаблоны?
varargs также используются в некоторых метапрограммировании (черты, реализованные с помощью SFINAE, например) из-за их свойства считаться последним при разрешении перегрузки. – bolov
@bolov круто! Я никогда не сталкивался с этим прецедентом. Звучит немного * слишком * умный для моего хорошего, хотя :) – user2079303
@bolov не могли бы вы дать более подробную информацию, даже пример кода или ссылку –