J'essaie donc de mettre en œuvre le produit de points ( https://en.wikipedia.org/wiki/Dot_product ) dans un certain type de C++ moderne et j'ai obtenu le code suivant :
#include <iostream>
template<class... Args>
auto dot(Args... args)
{
auto a = [args...](Args...)
{
return [=](auto... brgs)
{
static_assert(sizeof...(args) == sizeof...(brgs));
auto v1 = {args...}, i1 = v1.begin();
auto v2 = {brgs...}, i2 = v2.begin();
typename std::common_type<Args...>::type s = 0;
while( i1 != v1.end() && i2!= v2.end())
{
s += *i1++ * *i2++;
}
return s;
};
};
return a(std::forward<Args>(args)...);
}
int main()
{
auto a = dot(1,3,-5)(4,-2,-1);
std::cout << a << std::endl;
}
En ligne : https://gcc.godbolt.org/z/kDSney et aussi : cppinsights
Le code ci-dessus se compile et s'exécute correctement avec g++
Cependant clang
(et icc
y msvc
) s'en étouffent :
clang++ ./funcpp.cpp --std=c++17
./funcpp.cpp:12:4: error: 'auto' deduced as 'std::initializer_list<int>' in declaration of
'v1' and deduced as 'const int *' in declaration of 'i1'
auto v1 = {args...}, i1 = v1.begin();
^ ~~~~~~~~~ ~~~~~~~~~~
./funcpp.cpp:28:11: note: in instantiation of function template specialization
'dot<int, int, int>' requested here
auto a = dot(1,3,-5)(4,-2,-1);
^
1 error generated.
Maintenant, si je décompose la définition de v1
, v2
, i1
, i2
comme :
auto v1 = {args...} ;
auto i1 = v1.begin();
auto v2 = {brgs...};
auto i2 = v2.begin();
clang
y msvc
n'ont aucun problème, icc
s'étouffe encore :
<source>(10): error: static assertion failed
static_assert(sizeof...(args) == sizeof...(brgs));
^
detected during instantiation of "auto dot(Args...) [with Args=<int, int, int>]" at line 30
compilation aborted for <source> (code 2)
Execution build compiler returned: 2
Toutefois, si je supprime le static_assert
puis icc
n'a pas non plus de problème pour compiler le code.
Outre la question (typique) de savoir qui a raison et pourquoi :), la question concrète est la suivante :
Selon le [dcl.spec.auto]
:
si le type qui remplace le type de l'espace réservé n'est pas le même dans chaque déduction, le programme est mal formé
clang
a correctement identifié qu'il existe deux types différents définis dans la ligne en question : 'auto' deduced as 'std::initializer_list<int>' in declaration of 'v1' and deduced as 'const int *' in declaration of 'i1'
J'aimerais donc connaître votre opinion à ce sujet :
- ai-je trouvé une extension de g++ non documentée pour cette situation spécifique (non mentionnée dans le document https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/C_002b_002b-Extensions.html#C_002b_002b-Extensions ) puisque g++, à ma connaissance, gère correctement les différents types dans une liste d'auto-déclarations,
- ou par hasard g++ n'a pas déduit que les deux types étaient différents (... hm...)
- ou autre chose ?
Merci d'avoir lu cette longue question. (En prime, si quelqu'un peut répondre à la question de savoir pourquoi icc
échoue sur le static_assert
serait une excellente chose).