だから、私はドット積を実装しようとしています( https://en.wikipedia.org/wiki/Dot_product)を最新のC ++のいくつかのフレーバーで、次のコードを考え出しました:
#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
問題の行で2つの異なるタイプが定義されていることを正しく識別しました。'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 ++が2つのタイプを異なるものと推定しなかった(... hm ...)
- または、他の何か?
この長い質問を読んでいただきありがとうございます。(もし誰かがicc
失敗した理由に答えることができれば、ボーナスとしてstatic_assert
素晴らしいでしょう。)
auto v = { 1, 2, 3 }, i = v.begin();
。同じinsiedeラムダをコンパイルすることを理解していません。最小限の例: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)
ここの用途は何ですか?