2017-01-25 1 views
0

Disons que je veux avoir une fonction surchargée par deux versions comme ceci:Comment désambiguïser une fonction variadique avec un autre en C++

a) void query(const string& s); qui fait une requête SQL à un serveur.

b) void query(const string& s,...); qui construit une chaîne de requête donnée par une chaîne de format et des arguments à substituer. En interne, cette version ressemble (je cache les détails de ne pas trop compliquer la question):

va_list vargs; 
va_start(vargs, s); 
// ... call vsnprintf to build the query string 
// ... call the first version with the query string 
va_end(vargs); 

Notez que je veux aussi que cela fonctionne dans les deux MSVC et le CCG. Bien sûr, en écrivant comme ci-dessus, je ne peux pas pour l'appel suivant à cause de l'ambiguïté:

query("...");

Pour résoudre l'ambiguïté dans ce cas, je l'ai essayé plusieurs façons, mais aucun d'entre eux fonctionne:

1) les Réécrire comme:

void query(const string& s) { 
// ... 
} 

template<typename Value> 
void query(const string& s, Value value,...) { 
    va_list vargs; 
    va_start(vargs, s); 
    // ... 
} 

Ceci compile et fonctionne très bien dans MSVC, mais GCC se plaint d'un avertissement:

"second paramètre de va_start n'est pas le dernier argument nommé"

Même si j'ignore cet avertissement, cela ne fonctionne pas. D'une certaine manière vargs ne peut pas capturer value paramètre pour ce que j'essaie: va_start(vargs, s) ou va_start(vargs, value). Il me semble que GCC ne prend toujours que des paramètres sans nom dans vargs, peu importe ce que nous fournissons comme deuxième paramètre à va_start.

2) les Réécrire comme

void query(const string& s) { 
// ... 
} 

template<typename... Values> 
enable_if<(sizeof...(Values) > 0), void>::type 
query(const string& s, Values value...) { 
    va_list vargs; 
    va_start(vargs, s); 
    // ... 
} 

Encore une fois, cette compile et fonctionne avec MSVC. Mais GCC se plaint d'une erreur selon laquelle la 2e version est un modèle variadique plutôt qu'une fonction variadique, et va_start n'est pas autorisé à y être utilisé. Il semble que va_start dans GCC est intégré plutôt que de la bibliothèque.

Certaines personnes peuvent remarquer que dans les 2 versions, la 2ème version remplace la 1ère. Cela signifie que si je supprime la 1ère version et la place en interne dans la 2ème, tout ira bien. Mais j'ai une bonne raison de garder la 1ère version: je veux que les appels avec juste une chaîne pour aller directement sans appeler sans nécessité vsnprintf. Alors s'il vous plaît ne me suggère pas de cette façon.

J'ai aussi pensé à combiner la 1ère version dans la 2ème, puis comptez en interne le nombre d'arguments donnés pour savoir comment aller. Mais il ne semble pas y avoir de moyen standard pour le faire. La détermination du nombre d'arguments est possible avec des modèles variadiques mais pas avec des fonctions variadiques. Et si je passe en modèle variadique, je ne peux plus utiliser va_start dans GCC.

J'espère que quelqu'un peut vous aider !!

+1

Pourquoi les surcharger? Pourquoi ne pas leur donner des noms différents? Ils semblent faire des choses très différentes. – Carcigenicate

+0

"* Je veux que les appels avec juste une chaîne se passent directement sans appeler sans nécessité' vsnprintf'. * "- Avez-vous référencé cela? Quelle performance cela vous apporte-t-il? – melpomene

+0

@Carcigenicate: juste pour simplifier l'utilisation avec la transparence. – kien

Répondre

1

Je ne l'ai pas testé, mais ne fonctionne-t-il pas?

void query_varargs(const string &s, ...) { 
    va_list vargs; 
    va_start(vargs, s); 
    // ... 
} 

template<typename... Values> 
enable_if<(sizeof...(Values) > 0), void>::type 
query(const string& s, Values value...) { 
    query_varargs(s, ...value); 
} 

I.e. déplacez la fonctionnalité dans une autre fonction (query_varargs), puis passez à la version du modèle variadique query.

+0

Merci beaucoup, vous m'avez sauvé la vie! En fait, cela fait partie de cette bibliothèque: https://github.com/daotrungkien/mysql-cpp11 Maintenant, cela fonctionne parfaitement. – kien