4 votes

Fonction variadique sans argument nommé

J'ai remarqué que GCC et MSVC sont tous deux satisfaits du code suivant :

#include <iostream>
void foo(...);

int main()
{
    foo();
}

void foo(...)
{
    std::cout << "foo\n";
}

Plus précisément, le code a été exécuté sous GCC 6.2.0 et Visual Studio 2015.

Je sais que le C nécessite au moins un nommé précédant l'ellipse, qui permet de traiter un nombre quelconque d'arguments à l'aide d'outils spécialisés. va_start , va_args y va_end macros de <stdarg.h> (ici <cstdarg> ). Sinon, il ne sera même pas compilé.

Est-ce que le C++ a un traitement spécial pour la forme "ellipse pure" ou est-ce qu'elle ne convient pas pour récupérer les arguments, c'est-à-dire qu'elle est autorisée, mais complètement impraticable ?

4voto

paul-g Points 103

Les arguments de Variadiac C++ sont expliqués ici . Cette syntaxe est supportée en C++, mais les arguments ne sont pas accessibles :

Dans le langage de programmation C, au moins un paramètre nommé doit apparaître avant le paramètre ellipsé, donc printz(...); n'est pas valide.

En C++, cette forme est autorisée même si les arguments passés à de tels ne sont pas accessibles, et est communément utilisée comme surcharge surcharge de repli dans SFINAE, exploitant la priorité la plus basse de la conversion des ellipses dans la résolution des surcharges. Cette syntaxe pour les arguments variadiques a été introduite en 1987 dans le C++ sans la virgule avant l'ellipse. Lorsque C89 a adopté les prototypes de fonction de C++, il a remplacé la syntaxe avec une syntaxe nécessitant la virgule. Pour des raisons de compatibilité, C++98 accepte à la fois style C f(int n...) et le style C f(int n, ...)

2voto

Guillaume Racicot Points 1106

En C++, c'est autorisé parce que même s'il n'y a pas de paramètre nommé avant, la fonction ... ne sera qu'un argument variadique inaccessible.

En C, il n'y a pas de surcharges, et avoir une fonction qui reçoit seulement ... peut être une grande source d'erreur d'exécution. Les varargs inaccessibles ne sont pas utiles en C.

En C++, il est actuellement utilisé comme fonction de descente pour sfinae. Les compilateurs choisiront toujours une autre surcharge si possible avant de résoudre un appel à une fonction avec un paramètre variadique. C'est pratique pour les sfinae :

template<typename F, typename... Ts>
struct is_callable {
private:

    template<typename T, typename... Args>
    static decltype(
        static_cast<void>(std::declval<T>()(std::declval<Args>()...)),
        std::true_type{}
    ) test(int);

    template<typename...>
    static std::false_type test(...); // not a template variadic, classic vararg here.

public:
    // Here, the compiler will try the first version of the function
    // Because '...' is not the preferred overload
    // If the return type expression don't yield to a type, the compiler
    // will have no choice but to pick the variadic one,
    // resulting in a std::false_type
    using type = decltype(test<F, Ts...>(0));
};

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X