>

컴파일 타임에숫자 ...의 합을 계산하려고하지만 루프없이parameter pack를 반복하는 방법을 모르겠습니다.

#include <string>

template<int ...Numbers>
constexpr auto sum()
{
    //need to return sum of Numbers...
    //for(auto && i : {Numbers...})
    return 0;
}
template<int N>
void test()
{
    std::cout << "Sum of elements: " <<  N << " " << std::endl;   
}
int main()
{
    test<sum<1,5,7,6>()>();
}



  • 답변 # 1

    접이식 사용 (c ++ 17 필요) :

    template<int ...Numbers>
    constexpr auto sum()
    {
        return (Numbers + ...);
    }
    
    
    <시간>

    C ++ 14에서 도우미 함수와 함께 재귀를 사용하십시오 :

    constexpr int adder(int val = 0){
        return val;
    }
    template<class T, class ... Rest>
    constexpr auto adder(T t1, Rest ... rest) {
        return t1 + adder(rest...);
    }
    template<int ...Numbers>
    constexpr auto sum() {
        return adder(Numbers...);
    }
    
    

    실시간 데모

    결과 19.

  • 답변 # 2

    이 솔루션은사용 가능되었지만 std::accumulate 이후로는 사용할 수 없었던 솔루션입니다.  알고리즘이 constexpr 가 아닙니다 . 왜 그런지 궁금합니다. 어쩌면 constexpr 가 될 것입니다.  C ++ 23으로?

    어쨌든 std::accumulate 라고 가정 해 봅시다.   constexpr 였다 ‘즉, 귀하는 다음을 직접 구현할 필요가 없습니다.

    namespace std { // Again, just to be clear - this isn't actually in std right now
    template<class InputIt, class T>
    constexpr T accumulate(InputIt first, InputIt last, T init)
    {
        for (; first != last; ++first) {
            init = std::move(init) + *first;
        }
        return init;
    }
    } // namespace std
    
    

    이제 작성해야합니다 :

    template<int ...Numbers>
    constexpr auto sum() 
    {
    #if __cplusplus >= 201703L
        auto numbers = std::array{Numbers...};
    #else // assuming __cplusplus >= 201402L
        auto numbers = std::experimental::make_array(Numbers...);
    #endif
        return std::accumulate(numbers.begin(), numbers.end(), 0);
    }
    
    

    ... 이것은 C ++ 14 이상에서 작동합니다.

    이제 std::accumulate 의 constexpr + ranges 버전이 있다면 , 당신은 다음과 같이 쓸 것입니다 :

    template<int ...Numbers>
    constexpr auto sum()
    {
        return std::accumulate(std::array{Numbers...}, 0);
    }
    
    

    PS- init 라면 더 좋았을 것입니다  매개 변수가 기본적으로 T{} 로 초기화되었습니다. .

  • 답변 # 3

    c ++ 11 또는 c ++ 14에서는 hack으로 접기 표현을 얻을 수 있습니다.

    #include <type_traits> // std::common_type
    template <typename ... Args>
    constexpr auto sum(Args&&... args) -> typename std::common_type<Args...>::type
    {
        using unused = int[];
        using ReturnType = typename std::common_type<Args...>::type;
        ReturnType  result{};
        (void)unused { 0, (result += args, 0)...};
        return result;
    }
    
    

    이를 호출 할 수 있습니다 :

    test<sum(1,5,7,6)>();
    
    

    Variadic 템플릿 함수 (IMHO)를 만드는 자연스러운 방법과 비슷합니다. (온라인에서 C ++ 14 솔루션 라이브 참조)

    <시간>

    의 의견에서@einpoklum제안에 따라 C +에 대한 람다의 도움으로 동일한 기법 (런타임)을 보여주고 싶습니다 +11 및 C ++ 14 컴파일러 :

    #include <type_traits> // std::common_type
    template <int... Args>
    constexpr auto sum() -> typename std::common_type<decltype(Args)...>::type
    {
        using unused = int[];
        using ReturnType = typename std::common_type<decltype(Args)...>::type;
        return [](decltype(Args)... args) // or since C++14 : (auto&&... args) 
        {
            ReturnType result{};
            (void)unused {
            0, (result += args, 0)...
            };
            return result;
        }(Args...);
    }
    
    

    런타임에 있기 때문에 (이유 : 람다는 기본적으로 constexpr 가 아닙니다.  C ++ 17까지), test인스 턴 티아 온  불가능하다 (즉, test<sum<1, 2, 3>()>(); )로 이동합니다.

    그러나 C ++ 17 람다는 암시 적 constexpr 이기 때문에  달성 할 수 있습니다. C ++ 17에서 일반 접기 표현을 사용하므로 C ++ 11 또는 C ++ 14 컴파일러에 대한 OP의 관심사를 다루지 않으므로 단점이 다시 불필요합니다.

    <시간>

    여기에서 자세히 읽어보십시오 : 가변형 템플릿 기본 클래스로의 통화를 확장하려면 어떻게해야합니까?

  • 답변 # 4

    rafix07의 솔루션이 실제로 정확하지만 실제 함수 매개 변수를 사용하지 않으려면 완전히 삭제하고 대신 템플릿 매개 변수를 사용하십시오.

    template<int LastTerm = 0>
    constexpr auto sum()
    {
        return LastTerm;
    }
    template<int FirstTerm, int SecondTerm, int... Rest>
    constexpr auto sum()
    {
        return FirstTerm + SecondTerm + sum<Rest...>();
    }
    
    template<int N>
    void test()
    {
        std::cout << "Sum of elements: " <<  N << " " << std::endl;   
    }
    int main()
    {
        test<sum<1,5,7,6>()>();
    }
    
    

  • 답변 # 5

    "고전적인"접근 방식은 재귀입니다 :

    template <int...> struct Sum;
    template <>
    struct Sum<> : std::integral_constant<int, 0> { };
    template <int N, int... Ns>
    struct Sum<N, Ns...> : std::integral_constant<int, N + Sum<Ns...>::value> { };
    
    void test()
    {
      static_assert(Sum<8, 9, 10>::value == 27);
    }
    
    

  • 이전 unity3d - Unity VR UNET은 PC와 VR을 동일한 플레이어로 만듭니다
  • 다음 제약 조건 XCode ios Swift를 추가 한 후 Google지도에 배치 된 버튼이 사라짐