다른 C ++ 컴파일러간에 자동 유형이 일치하지 않습니다.


10

그래서 현대 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/kDSneycppinsights

좋게 함께 컴파일하여 실행하는 상기 코드 g++하지만 clang(그리고 iccmsvc그것에) 초크 :

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'따라서 다음 사항에 대한 귀하의 의견을 듣고 싶습니다.

이 긴 질문을 읽어 주셔서 감사합니다. (왜 누군가가 대답 할 수 있다면 보너스로 icc실패하는 것이 static_assert좋을 것입니다.)


1
std::forward<Args>(args)여기 의 용도는 무엇입니까 ?
Evg.

test.cpp : 'int main ()'함수에서 : test.cpp : 4 : 5 : 오류 : 'auto'에 대한 일관되지 않은 추론 : 'long int'와 'double'4 | 자동 i = 0l, f = 0.0; | ^ ~~~ g ++에서는 일반적으로 이것을 확장하지 않는 것 같습니다.
n314159

유형을 인쇄하면 std :: initializer_list <int>, int const *가 나타납니다. std :: initializer_list <int>, int const * (g ++)는 다른 유형을 추론합니다.
n314159

3
GCC 가 컴파일되지 않습니다 auto v = { 1, 2, 3 }, i = v.begin(); . 동일한 insiede 람다를 컴파일한다는 것을 이해하지 마십시오. 최소 예 : gcc.godbolt.org/z/a5XyxU . 사용자 정의 functor ( gcc.godbolt.org/z/eYutyK ) 또는 템플릿 함수 ( gcc.godbolt.org/z/jnEYXh) 내에서도 컴파일 됩니다.
Daniel Langr

2
@underscore_d 나는 그렇게 생각합니다. 가장 작은 예는 다음 template <typename T> void f(T a) { auto v = {a}, i = v.begin(); }과 같이 호출 될 때 f(1);입니다. 다시 작성 void f(int a) { /* same body */ }하면 컴파일 오류가 발생합니다.
Daniel Langr

답변:


2

내 의견에서 확장 :

g ++은 항상 이것을하지는 않지만 예제를 고려 auto i = 0l, f = 0.0;하면 오류가 발생합니다.

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;

프로그램을 컴파일하고 변수 유형을 인쇄하면 ( 이 메소드 사용 ) 다음과 같은 결과가 나타납니다.

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

-std=c++17 -pedantic -Wall -Wextra경고 나 오류가없는 플래그와 함께 gcc 버전 9.2.0 사용

표준에 대한 귀하의 의견에 따르면이 프로그램은 잘못 작성되었으며 표준 달리 명시되지 않은 경우 (이 경우에는 그렇지 않은 경우) 진단 메시지 (경고 또는 오류)가 발생하도록 지정합니다. 따라서 이것이 gcc의 버그라고 말할 것입니다.

그것은이다 알려진 버그 .


매우 편리한 버그이기 때문에 ... 일부는 기능이라고 주장 할 수도 있습니다 .D 통찰력을 가져 주셔서 감사합니다!
Ferenc Deak

누군가 g++이것 에 대해 버그를 제기 할 수 있다면 좋을 것 입니다.
underscore_d

1
나는 전에 그것을 한 적이 없지만 몇 시간 안에 그것을 볼 수 있습니다.
n314159

gcc.gnu.org/bugzilla/show_bug.cgi?id=92509 합리적인 버그 리포트 가기를 바랍니다.
n314159

0

static_assertICC 의 실패는 분명히 버그입니다. static_assert별도의 기능 으로 이동하여 간단한 해결 방법을 찾았습니다 . 매우 우아한 솔루션은 아니지만 작동합니다.

약간 수정하면 GCC, Clang 및 ICC로 컴파일되는 코드입니다.

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

ICC에 대한 버그가 있습니까? :-)
underscore_d

ICC에 분명히 버그가 있다고 말 했으므로 누군가가 이미 제출 한이 버그에 대한보고가 있는지 궁금합니다. 그렇지 않은 경우 지금 만들 수 있습니다.
underscore_d

1
@underscore_d, 아직 확인하지는 않았지만 그럴 것입니다.
Evg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.