Farklı c ++ derleyicileri arasında otomatik türlerin yanlış eşleştirilmesi


10

Bu yüzden, nokta ürününü ( https://en.wikipedia.org/wiki/Dot_product ) modern C ++ 'ın bazı lezzetlerinde uygulamaya çalışıyorum ve aşağıdaki kod ile geldim:

#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;
}

Çevrimiçi: https://gcc.godbolt.org/z/kDSney ve ayrıca: cppinsights

Yukarıdaki kod iyi derler ve iyi çalışır g++, ancak clang(ve iccve msvc) boğulma:

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.

Şimdi, tanımını bölerseniz v1, v2, i1, i2gibi:

auto v1 = {args...} ;
auto i1 = v1.begin();
auto v2 = {brgs...};
auto i2 = v2.begin();

clangve msvcproblemleri yok, icchala boğuluyor:

<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

Ancak ben rahatsızlık kaldırmak o static_assertzaman iccya da kod derleme hiçbir sorunları var.

Ve (tipik) sorunun yanında: hangisi doğru ve neden :) somut soru:

Göre [dcl.spec.auto]:

yer tutucu türünün yerini alan tür her kesinti için aynı değilse, program kötü biçimlendirilir

clangsöz konusu satırda iki farklı tür tanımlandığını doğru bir şekilde tespit etti 'auto' deduced as 'std::initializer_list<int>' in declaration of 'v1' and deduced as 'const int *' in declaration of 'i1':

Bu uzun soruyu okuduğunuz için teşekkürler. (Birisi neden biri iccbaşarısız olursa cevap verebilir eğer bir bonus static_assertolarak harika olurdu.)


1
Burada ne yararı std::forward<Args>(args)var?
Evg

test.cpp: 'int main ()' işlevinde: test.cpp: 4: 5: hata: 'auto' için tutarsız kesinti: 'long int' ve sonra 'double' 4 | otomatik i = 0l, f = 0.0; | ^ ~~~ g ++ ile, genel olarak bunu genişletmiyor gibi görünüyor.
n314159

türleri yazdırmak bize verir: std :: initializer_list <int>, int const * std :: initializer_list <int>, g ++ içinde int const *, bu yüzden farklı türleri çıkarır.
n314159

3
GCC derlenmez auto v = { 1, 2, 3 }, i = v.begin(); . Aynı insiede lambda'yı derlediğini anlamayın. En az örnek: gcc.godbolt.org/z/a5XyxU . Kullanıcı tanımlı bir işlevin içinde bile derlenir: gcc.godbolt.org/z/eYutyK veya bir şablon işlevi: gcc.godbolt.org/z/jnEYXh .
Daniel Langr

2
@underscore_d Sanırım. Çok asgari örnek, template <typename T> void f(T a) { auto v = {a}, i = v.begin(); }çağrıldığında, örn f(1);. void f(int a) { /* same body */ }Derleme hatasına neden olarak yeniden yazılmıştır .
Daniel Langr

Yanıtlar:


2

Yorumlarımdan genişleyen:

g ++ bunu her zaman yapmaz, örneği düşünün auto i = 0l, f = 0.0;, hatayı verir:

test.cpp: In function int main()’:
test.cpp:4:5: error: inconsistent deduction for auto’: long int and then double
    4 |     auto i = 0l, f = 0.0;

Programınızı derler ve değişken türlerini yazdırırsak ( bu yöntemle ), aşağıdaki çıktıyı alırız:

v1: std::initializer_list<int>, i1: int const*
v2: std::initializer_list<int>, i2: int const*

-std=c++17 -pedantic -Wall -Wextrauyarı veya hata olmadan bayrakları ile gcc sürüm 9.2.0 kullanarak .

Standardın Yorumunuza göre bu program kötü şekillendirilmiş ve standart belirtir (Bu durumda, değil mi) Aksi belirtilmedikçe tanısal bir mesaj (uyarı veya hata) orada yayılan gerektiğini. Bu yüzden bu gcc bir hata olduğunu söyleyebilirim.

Öyle bilinen bir hata .


Çok uygun bir hata olduğu için ... bazıları bunun bir özellik olduğunu iddia edebilir: D Görüşleriniz için teşekkürler!
Ferenc Deak

Birisi buna karşı bir hata dosyalayabilirse harika olurdu g++.
underscore_d

1
Bunu daha önce hiç yapmadım ama birkaç saat içinde bakabilirim.
n314159

gcc.gnu.org/bugzilla/show_bug.cgi?id=92509 Umarım bu mantıklı bir hata raporudur.
n314159

0

static_assertICC kesinlikle bir hata olduğunu başarısız. static_assertAyrı bir işleve geçerek basit bir çözüm buldum . Çok zarif bir çözüm değil, ama işe yarıyor.

Küçük değişikliklerle, bu GCC, Clang ve ICC ile derlenen koddur:

template<std::size_t size, class... Args>
void args_no_guard(Args... args)
{
    static_assert(sizeof...(args) == size);
}

template<class... Args>
auto dot(Args... args)
{
    return [=](auto... brgs)
    {
        constexpr auto n = sizeof...(args);
        args_no_guard<n>(brgs...);

        using T = std::common_type_t<decltype(args)..., decltype(brgs)...>;
        const T v1[]{static_cast<T>(args)...};
        const T v2[]{static_cast<T>(brgs)...};

        T dot = 0;
        for (std::size_t i = 0; i < n; ++i)
            dot += v1[i] * v2[i];
        return dot;
    };
}

Bunun için ICC'ye karşı bir hata var mı? :-)
underscore_d

ICC'de açıkça bir hata olduğunu söyledin, bu yüzden birinin bu hata hakkında zaten bir rapor gönderdiğini merak ediyorum. Değilse, bu bir tane oluşturmak için iyi bir zaman olabilir.
underscore_d

1
@underscore_d, henüz kontrol etmedim, ama yapacağım.
Evg
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.