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

이 긴 질문을 읽어 주셔서 감사합니다. (왜 누군가가 대답 할 수 있다면 보너스로 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.