ดังนั้นฉันกำลังพยายามที่จะใช้ผลิตภัณฑ์ dot ( https://en.wikipedia.org/wiki/Dot_product ) ในบางรสชาติของ C ++ ที่ทันสมัยและมาพร้อมกับรหัสต่อไปนี้:
#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;
}
ออนไลน์: https://gcc.godbolt.org/z/kDSneyและ: cppinsights
โค้ดข้างต้นรวบรวมและดำเนินการอย่างดีด้วยg++
อย่างไรก็ตามclang
(และicc
และmsvc
) ทำให้หายใจไม่ออกบน:
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.
ตอนนี้ถ้าผมเลิกนิยามของv1
, v2
, i1
, i2
เช่น:
auto v1 = {args...} ;
auto i1 = v1.begin();
auto v2 = {brgs...};
auto i2 = v2.begin();
clang
และmsvc
ไม่มีปัญหาicc
ยังคงสำลัก:
<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
อย่างไรก็ตามหากฉันลบการละเมิดออกไปstatic_assert
ก็icc
ไม่มีปัญหาในการรวบรวมรหัสเช่นกัน
และนอกเหนือจากคำถาม (ทั่วไป): ซึ่งถูกและทำไม :) คำถามที่เป็นรูปธรรมคือ:
ตาม[dcl.spec.auto]
:
หากประเภทที่แทนที่ประเภทตัวยึดตำแหน่งไม่เหมือนกันในแต่ละการหักค่าโปรแกรมจะเกิดรูปแบบไม่ถูกต้อง
clang
ระบุอย่างถูกต้องว่ามีคำถามอยู่สองประเภทที่แตกต่างกันที่กำหนดไว้: 'auto' deduced as 'std::initializer_list<int>' in declaration of 'v1' and deduced as 'const int *' in declaration of 'i1'
ดังนั้นฉันต้องการฟังความคิดเห็นของคุณว่า:
- ฉันมีส่วนขยาย g ++ ที่ไม่มีเอกสารพิจารณาสถานการณ์นี้โดยเฉพาะ (ไม่ได้กล่าวถึงในhttps://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/C_002b_002b-Extensions.html#C_002b_002b-Extensions ) ตั้งแต่ g ++ ถึงความรู้ของฉัน จัดการประเภทต่าง ๆ ในรายการประกาศอัตโนมัติอย่างถูกต้อง
- หรือโอกาสใดก็ตามที่ g ++ ไม่ได้อนุมานว่าทั้งสองประเภทจะแตกต่างกัน (... hm ... )
- หรืออย่างอื่น?
ขอขอบคุณที่อ่านคำถามยาว ๆ นี้ (เป็นโบนัสหากมีใครตอบได้ว่าทำไมความicc
ล้มเหลวในการทำเช่นstatic_assert
นั้นจึงยอดเยี่ยม)
auto v = { 1, 2, 3 }, i = v.begin();
ไม่เข้าใจว่ามันรวบรวมแลมบ์ดา insiede เดียวกัน ตัวอย่างน้อยที่สุด: gcc.godbolt.org/z/a5XyxU มันยังรวบรวมภายในที่ผู้ใช้กำหนด functor: gcc.godbolt.org/z/eYutyKหรือฟังก์ชั่นแม่แบบ: gcc.godbolt.org/z/jnEYXh
template <typename T> void f(T a) { auto v = {a}, i = v.begin(); }
f(1);
เขียนซ้ำเป็นvoid f(int a) { /* same body */ }
สาเหตุของข้อผิดพลาดในการรวบรวม
std::forward<Args>(args)
ที่นี่คืออะไร?