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( iccvà 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, i2như:
auto v1 = {args...} ;
auto i1 = v1.begin();
auto v2 = {brgs...};
auto i2 = v2.begin();
clangvà msvckhông có vấn đề gì, iccvẫ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_assertthì icccũ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
clangxá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 iccthất bại trên static_assertsẽ 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ì?