L’expansion du pack de parameters est inversée par le compilateur VS2015.
J’ai le code suivant:
#include #include template void f_Swallow(T &&...) { } template std::vector f(T ...arg) { std::vector result; f_Swallow ( [&]() { result.push_back(arg); return true; } ()... ) ; return result; } using namespace std; int main() { auto vec = f(1,2,3,4); for (size_t i = 0; i < vec.size(); ++i) cout << vec[i] << endl; }
Lorsque j’exécute ce code dans XCode (clang-700.1.81), j’obtiens ce résultat:
1 2 3 4
Mais le même code exécuté dans VS2015 produit cette sortie:
4 3 2 1
Pourquoi les packs de parameters sont-ils développés différemment selon le compilateur? Est-il possible de résoudre le problème sans vérifier la version de la plate-forme et du compilateur? La norme ne garantit-elle rien sur l’ordre d’expansion?
Ce n’est pas l’ordre de développement des paquets de parameters qui est différent, c’est l’ordre d’évaluation des arguments de la fonction.
f_Swallow ( [&]() { result.push_back(arg); return true; } ()... ) ;
Par souci de concision, laissez simplement à ce lambda le nom funcN
où N
est le numéro du paramètre. Compte tenu de quatre arguments, le pack de parameters sera développé par tout compilateur conforme en ceci:
f_Swallow(func1(), func2(), func3, func4()) ;
L’ordre d’évaluation des arguments de fonction n’est pas spécifié dans C ++. Le compilateur pourrait les évaluer dans l’ordre (comme votre version de Clang), dans l’ordre inverse (comme votre version de MSVC), ou dans n’importe quel ordre. Vous ne pouvez pas compter sur l’ordre d’évaluation.
Pour obtenir ce que vous voulez, vous pouvez placer les expressions dans un contexte dans lequel l’ordre d’évaluation est spécifié. Par exemple:
template std::vector f(T ...arg) { std::vector result; (void)std::initializer_list { (result.push_back(arg), 0)... }; return result; }
En C ++ 17, vous pourrez effectuer les opérations suivantes avec des expressions de pliage :
template std::vector f(T ...arg) { std::vector result; (result.push_back(arg), ...); return result; }
Je pensais que cela pourrait aussi être écrit comme ceci:
template std::vector f(T ...arg) { std::vector result{ arg... }; return result; }
Pas besoin de créer dummy std :: initializer_list