इसलिए, मैं आधुनिक सी ++ के कुछ स्वाद में डॉट उत्पाद ( https://en.wikipedia.org/wiki/Dot_product ) को लागू करने की कोशिश कर रहा हूं और निम्नलिखित कोड के साथ आया:
#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/onbuildocs/gcc-9.2.0/gcc/C_002b_002b-Extensions.html#C003b_002b-Extensions में जी) के बाद से मेरी जानकारी के अनुसार ऑटो घोषणा सूची में विभिन्न प्रकारों को सही ढंग से संभालता है,
- या किसी भी संयोग से g ++ ने दो प्रकारों को अलग करने के लिए कटौती नहीं की (... hm ...)
- या कुछ और?
इस लंबे प्रश्न के माध्यम से पढ़ने के लिए धन्यवाद। (एक बोनस के रूप में अगर कोई जवाब दे सकता है कि क्यों महान होगा icc
पर विफल रहता है static_assert
।)
auto v = { 1, 2, 3 }, i = v.begin();
। समझ में नहीं आता है कि यह एक ही अपमानित लैम्ब्डा को संकलित करता है। मिनिमल उदाहरण: gcc.godbolt.org/z/a5XyxU । यहां तक कि यह एक उपयोगकर्ता-निर्धारित फ़नकार के अंदर भी संकलित है: 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)
है?