Vì vậy, tôi đang cố gắng triển khai sản phẩm chấm ( https://en.wikipedia.org/wiki/Dot_product ) trong một số hương vị của C ++ hiện đại và đưa ra mã sau:
#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;
}
Trực tuyến: https://gcc.godbolt.org/z/kDSney và cả: cppinsights
Đoạn mã trên biên dịch và thực thi độc đáo với g++
, tuy nhiên clang
( icc
và msvc
) bị sặc trên nó:
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.
Bây giờ, nếu tôi phá vỡ các định nghĩa của v1
, v2
, i1
, i2
như:
auto v1 = {args...} ;
auto i1 = v1.begin();
auto v2 = {brgs...};
auto i2 = v2.begin();
clang
và msvc
không có vấn đề gì, icc
vẫn bị sặc:
<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
Tuy nhiên nếu tôi loại bỏ vi phạm static_assert
thì icc
cũng không có vấn đề biên dịch mã.
Và bên cạnh câu hỏi (điển hình): câu nào đúng và tại sao :) câu hỏi cụ thể là:
Theo [dcl.spec.auto]
:
nếu loại thay thế loại giữ chỗ không giống nhau trong mỗi lần khấu trừ, chương trình sẽ không được định dạng
clang
xác định chính xác rằng có hai loại khác nhau được xác định trong dòng đang đề cập: 'auto' deduced as 'std::initializer_list<int>' in declaration of 'v1' and deduced as 'const int *' in declaration of 'i1'
vì vậy tôi muốn nghe ý kiến của bạn cho dù:
- tôi đã nhấn một số tiện ích mở rộng g ++ không có giấy tờ khi xem xét tình huống cụ thể này (không được đề cập trong https://gcc.gnu.org/onlinesocs/gcc-9.2.0/gcc/C_002b_002b-Extensions.html#C_002b_002b-Extensions ) kể từ g ++ theo hiểu biết của tôi xử lý chính xác các loại khác nhau trong danh sách khai báo tự động,
- hoặc bằng mọi cách, g ++ đã không suy ra hai loại là khác nhau (... hm ...)
- hay cái gì khác?
Cảm ơn đã đọc qua câu hỏi dài này. (Như một phần thưởng nếu ai đó có thể trả lời tại sao icc
thất bại trên static_assert
sẽ rất tuyệt.)
auto v = { 1, 2, 3 }, i = v.begin();
. Đừng hiểu rằng nó biên dịch cùng lambda insiede. Ví dụ tối thiểu: gcc.godbolt.org/z/a5XyxU . Nó thậm chí còn biên dịch bên trong một functor do người dùng định nghĩa: gcc.godbolt.org/z/eYutyK hoặc một hàm mẫu: gcc.godbolt.org/z/jnEYXh .
template <typename T> void f(T a) { auto v = {a}, i = v.begin(); }
, khi được gọi, ví dụ, như f(1);
. Viết lại là void f(int a) { /* same body */ }
nguyên nhân lỗi biên dịch.
std::forward<Args>(args)
ở đây là gì?