因此,我试图以某种现代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,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 lambda。最小示例: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(); }
当调用时,非常小的示例是as f(1);
。重写为void f(int a) { /* same body */ }
会导致编译错误。
std::forward<Args>(args)
这里有什么用?