Bu yüzden, nokta ürününü ( https://en.wikipedia.org/wiki/Dot_product ) modern C ++ 'ın bazı lezzetlerinde uygulamaya çalışıyorum ve aşağıdaki kod ile geldim:
#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;
}
Çevrimiçi: https://gcc.godbolt.org/z/kDSney ve ayrıca: cppinsights
Yukarıdaki kod iyi derler ve iyi çalışır g++
, ancak clang
(ve icc
ve msvc
) boğulma:
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.
Şimdi, tanımını bölerseniz v1
, v2
, i1
, i2
gibi:
auto v1 = {args...} ;
auto i1 = v1.begin();
auto v2 = {brgs...};
auto i2 = v2.begin();
clang
ve msvc
problemleri yok, icc
hala boğuluyor:
<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
Ancak ben rahatsızlık kaldırmak o static_assert
zaman icc
ya da kod derleme hiçbir sorunları var.
Ve (tipik) sorunun yanında: hangisi doğru ve neden :) somut soru:
Göre [dcl.spec.auto]
:
yer tutucu türünün yerini alan tür her kesinti için aynı değilse, program kötü biçimlendirilir
clang
söz konusu satırda iki farklı tür tanımlandığını doğru bir şekilde tespit etti 'auto' deduced as 'std::initializer_list<int>' in declaration of 'v1' and deduced as 'const int *' in declaration of 'i1'
:
- b ++ 'dan beri bu özel durumu ( https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/C_002b_002b-Extensions.html#C_002b_002b-Extensions' da belirtilmemiş ) göz önüne alındığında belgelenmemiş bazı g ++ uzantılarına çarptım mı otomatik bildirim listesindeki farklı türleri doğru şekilde işler,
- ya da herhangi bir şans eseri g ++ iki türün farklı olduğunu çıkarmadı (... hm ...)
- veya başka bir şey?
Bu uzun soruyu okuduğunuz için teşekkürler. (Birisi neden biri icc
başarısız olursa cevap verebilir eğer bir bonus static_assert
olarak harika olurdu.)
auto v = { 1, 2, 3 }, i = v.begin();
. Aynı insiede lambda'yı derlediğini anlamayın. En az örnek: gcc.godbolt.org/z/a5XyxU . Kullanıcı tanımlı bir işlevin içinde bile derlenir: gcc.godbolt.org/z/eYutyK veya bir şablon işlevi: gcc.godbolt.org/z/jnEYXh .
template <typename T> void f(T a) { auto v = {a}, i = v.begin(); }
çağrıldığında, örn f(1);
. void f(int a) { /* same body */ }
Derleme hatasına neden olarak yeniden yazılmıştır .
std::forward<Args>(args)
var?