Szablony varariadic mają wiele zalet, ale czy istnieją okazje, aby zamiast nich używać funkcji variadic w stylu C (używając <cstdarg>
)?Czy istnieje przypadek, w którym funkcje vararg powinny być preferowane w stosunku do szablonów variadic?
Odpowiedz
Jeśli udostępniasz C API z implementacją C++, szablony nie są opcją dla interfejsu API. Varargs są.
Jeśli potrzebujesz obsługi kompilatora, który nie obsługuje C++ 11 lub nowszego standardu, szablony variadic nie są dostępne. Varargs są.
Jeśli potrzebujesz firewalla kompilacyjnego. To znaczy. musisz ukryć implementację funkcji z nagłówka, wtedy szablon variadic nie jest opcją. Varargs są.
W systemach z ograniczoną pamięcią (osadzonych) różne funkcje generowane przez szablon mogą wprowadzać zbyt duże rozrosty. Powiedział, że takie systemy są zwykle również w czasie rzeczywistym, w którym to przypadku varargs może być również niedopuszczalne ze względu na rozgałęzienia i użycie stosu.
chcę dodać do excellent answer of @user2079303
varargs wykorzystywane są również w pewnym metaprogramowanie (cech realizowanego z SFINAE na przykład), ze względu na ich właściwości są uważane za ostatni od rozdzielczości przeciążenia.
Powiedzmy chcemy wdrożyć cechę, aby wykryć, czy klasa jest constructible od niektórych rodzajów (coś jak std::is_constructible:
Uproszczony nowoczesna realizacja pójdzie tak (to nie jedyny sposób: jak wspomniano, void_t
może również be used to implement the trait i wkrótce (? 2020) nie będziemy potrzebować każdy z tych sztuczek jak concepts są w drodze z klauzulą require
jako obywatela pierwszej klasy):
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;
};
To działa, ponieważ od SFINAE: kiedy instantiati ng test
, jeśli semantyka jest nieważna z powodu jakiegoś dependent name, to nie jest to trudny błąd, zamiast tego przeciążenie jest po prostu ignorowane.
Jeśli chcesz dowiedzieć się więcej o sztuczkach rysunkowych i ich zastosowaniu oraz o tym, jak działają, możesz przeczytać dalej: sfinae idiom, member detector idiom, enable_if idiom.
Więc z typem X
, które mogą być wykonane z zaledwie 2 wskazówki:
struct X { X(int, int) {}; };
możemy uzyskać te wyniki:
Is_constructible<X, int, int>::value // true
Is_constructible<X, int>::value; // false
Teraz powstaje pytanie, czy możemy zastąpić test varargs z szablony variadic:
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;
};
Odpowiedź brzmi nie (przynajmniej nie t bezpośrednia wymiana).Kiedy instancji
Is_constructible_broken<X, int, int>::value
otrzymujemy błąd:
error: call of overloaded '
test(int, int)
' is ambiguous
ponieważ oba przeciążenia są opłacalne i oba mają taką samą rangę „” w rozdzielczości przeciążenia. Pierwsza implementacja z varargs działa, ponieważ nawet jeśli oba przeciążenia są wykonalne, szablon wariadyczny jeden jest preferowany w porównaniu z wariantem vararg.
Okazuje się, że faktycznie można to zrobić przy użyciu szablonów variadic. Sztuką jest, aby dodać sztuczną parametr test
to jest idealne dopasowanie dla pierwszego przeciążenia i konwersja do drugiego:
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;
};
Ale myślę, że varargs jest bardziej jasne w tej sprawie.
Zauważ, że 'void_t' może być użyte do stworzenia cech zamiast użycia elipsy. – Jarod42
@ Jarod42 tak, a wkrótce będzie to również przestarzałe przez [wymóg klauzuli] (http://en.cppreference.com/w/cpp/language/constraints) – bolov
Preferuję użycie 'struct high_overload_priority: low_overload_priority {};' ponad 'int' /' long', aby zamówić przeciążenie. – Jarod42
vararg umożliwia używanie __attribute__ format
. Na przykład.
void debug(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void f(float value)
{
debug("value = %d\n", value); // <- will show warning.
}
Niestety nie można tego osiągnąć przy użyciu szablonów variadic.
Edytowane: Jak podkreślił Vladimir, zapomniałem wspomnieć, że __attribute__ format
nie jest częścią standardu, jednak obsługuje go zarówno GCC, jak i Clang (ale nie Visual Studio). Aby uzyskać więcej informacji, zobacz: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes
Sugerowałbym, żebyś wstawił link użycia formatu __attribute__, ponieważ nie jest w standardzie. Uważam też, że dobrze jest pokazać niektóre z kompilatorów, których używa. Znam tylko GCC. –
https://gc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html –
- 1. Preferuj niektóre funkcje w stosunku do ADL
- 2. Czy nazwane funkcje lub anonimowe funkcje są preferowane w JavaScript?
- 3. Kolejny przypadek, w którym spacja ma znaczenie (być może?)
- 4. Czy mogę używać szablonów variadic w lambda?
- 5. Czy nazwy reprezentujące typy szablonów powinny być pojedynczymi znakami?
- 6. Ekstrakcje szablonów Variadic
- 7. Rozszerzenie zestawu szablonów Variadic
- 8. Funkcje Qt i variadic
- 9. Czy metatagi powinny być kodowane w HTML?
- 10. nie może zrozumieć szablonów variadic w C++
- 11. SFINAE z klasami szablonów variadic?
- 12. Czy istnieje alternatywa C# do parametrów vararg Java?
- 13. Czy języki programowania powinny być intuicyjne?
- 14. SaltStack: W instrukcji watch, jak określić katalog, w którym powinny być śledzone wszystkie pliki?
- 15. Wiele pakiet parametrów Variadic dla klasy szablonów
- 16. Argumenty kontenera argumentu macierzy szablonów Variadic
- 17. Czy IBOutlety powinny być ivars lub właściwości?
- 18. Multika map za pomocą szablonów variadic
- 19. Czy obiekty enum powinny być bezpaństwowcami?
- 20. Czy jednostki miary powinny być zlokalizowane?
- 21. Czy konteksty danych powinny być statyczne?
- 22. Czy instancje obiektu modelu django powinny być przekazywane do selera?
- 23. Python: czy istnieje przypadek użycia do zmiany klasy instancji?
- 24. Funkcje szablonów i odliczanie parametrów
- 25. Czy klasy warstwy usług powinny być pojedynczymi?
- 26. Jakie dokumenty powinny być przechowywane w kontroli wersji i jak powinny być przechowywane?
- 27. Uniwersalna inicjacja agregacji za pomocą szablonów variadic
- 28. sprawdź parametry szablonów variadic dla unikalności
- 29. Czy istnieje przykład, dlaczego Equals/GetHashCode powinny być nadpisywane w NHibernate?
- 30. W jaki sposób powinny być zapisywane notatki do wydania?
varargs są również używane w niektórych metaprogrammingach (cechy wprowadzane na przykład w SFINAE) z powodu ich właściwości, która jest uważana za ostatnią na rozdzielczość przeciążania. – bolov
@bolov fajne! Nigdy nie spotkałem się z tym przypadkiem użycia. Brzmi też * zbyt * sprytnie dla mojego dobra :) – user2079303
@bolov czy mógłbyś podać więcej szczegółów, nawet przykład kodu lub link –