因此,我试图以某种现代C ++的形式实现点积(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,-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>]" 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'
,所以我想听听您的意见是否:
- 考虑到这种特殊情况(https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/C_002b_002b-Extensions.html#C_002b_002b-Extensions中未提及),我是否遇到了一些未公开的g ++扩展名,因为据我所知g ++可以正确处理自动声明列表中的不同类型,
- 或者g ++未能偶然推断出两种类型是不同的(... hm ...)
- 还是其他?
感谢您阅读这个冗长的问题。
(如果有人能够回答为什么icc
在static_assert
上失败的原因,这是很好的选择。)