일반 유형으로 특정 유형의 STL 컨테이너


25

특정 유형의 컨테이너를 std::string매개 변수로 사용하는 함수를 만들 수있는 방법이 있습니까?

void foo(const std::container<std::string> &cont)
{
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

모든 유형의 stl 컨테이너에 대해 입력으로 호출합니까? 위처럼?

std::set<std::string> strset;
std::vector<std::string> strvec;
std::list<std::string> strlist;

foo(strset);
foo(strvec);
foo(strlist);

2
네, 템플릿 함수라고합니다. ;)
Ulrich Eckhardt

2
종종 한 쌍의 반복자를 전달하는 것이 더 좋습니다 (각각 컨테이너의 시작과 끝을 나타냄). 반복자가 함수의 요구 사항을 충족하는 한, 어떤 유형의 컨테이너에서 얻은 것인지는 중요하지 않습니다 (종종 예외가 있습니다).
피터

답변:


21

컨테이너 유형에 대한 템플리트 템플리트 매개 변수 를 사용 foo하여 함수 템플리트를 작성할 수 있습니다 .

예 :

template<template<typename...> typename C>
void foo(const C<std::string> &cont)
{
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

라이브


더 일반화 할 수 있다고 생각합니다. 내 대답을 참조하십시오.
theWiseBro

Lars의 답변 은 C 스타일 배열에서도 작동하기 때문에 더 좋습니다.
Ayxan

1
@theWiseBro 네, 일반적으로 좋은 생각입니다. 그러나 OP는 특정 유형으로 사용하기를 원한다고 생각합니다 std::string.
songyuanyao

3
@theWiseBro 정확하게. OP는 하나의 특정 유형으로 작동해야한다고 말했다 . 따라서 더 일반화하면 이점이 없습니다.
스 필러

1
@theWiseBro 나는 당신이 무슨 뜻인지 이해합니다. 나는 OP의 원래 의도에 대해 확신하지 못한다. OP에 설명해야 할 수도 있습니다. :)
songyuanyao

6

foo다른 경우 에 과부하 를 원하느냐에 따라

// Doesn't participate in overload resolution when not applicable
template<typename Container, typename = std::enable_if_t<std::is_same_v<typename Container::value_type, std::string>>>
void foo(const Container &cont) {
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

// simpler
template<typename Container>
void foo(const Container &cont) {
   static_assert(std::is_same_v<typename Container::value_type, std::string>, "Container must contain std::string")
   for(std::string val: cont) {
      std::cout << val << std::endl;
   }
}

다음 std::is_same과 같은 다른 테스트를 사용 std::is_convertible하여 허용 할 수 있습니다.

std::vector<char *> c_strings;
foo(c_strings);

0

대신 반복자를 사용하는 것이 좋습니다. 중간 결과는 다음과 같습니다

template<typename Iter>
void foo(Iter begin, Iter end) {
  using T = decltype(*begin);
  std::for_each(begin, end, [] (cons T & t) {
    std::out << t << '\n';
  }
}

이제 호출 가능한 템플릿을 사용하십시오.

template<typename Iter, typename Callable>
void foo(Iter begin, Iter end, Callable & c) {
  std::for_each(begin, end, c);
}

우리는 STL이 이미 제공하는 것을 사용하는 법을 배웠습니다.


-1

@songyuanyao의 답변에 덧붙여서 다음과 같이 더 일반화 할 수 있다고 생각합니다.

template<template<typename...> typename C, typename ... D>
void foo(const C<D...> &cont)
{
   for(const auto& val: cont) {
      std::cout << val << std::endl;
   }
}

1
이것은 요소 유형을 std :: string으로 제한하지 않으므로 질문에 대답하지 않습니다.
사샤

@Sasha 이것은 std :: string에 고정되어 있지 않지만 더 일반화 된 것이 사실입니다. OP는 특정 유형을 사용하려고합니다. 오늘 그가 std :: string을 사용하고 있고 내일에 MyCustomString을 대신 사용하고 싶다고 가정 해보십시오. 그가 한곳에서 코드를 편집하기 만하면되기 때문에 유지하기가 쉽지 않습니까?
theWiseBro

그러나 이것은로 제한하는 방법을 표시하지 않습니다 특히 "컨테이너 가지고 싶었던 querent - 표준 : : 문자열 또는 MyCustomString 요소 특정 유형을 ". 그대로 템플릿으로 발생하는 모든 유형을 허용하며 그 시점에서 단일 <typename C>에서 대신 템플릿을 지정하는 이유는 무엇입니까? 그것은 훨씬 간단하고 약간 더 일반화되어 있습니다-예를 들어 std :: string (일명 std :: basic_string <char>) 컨테이너로 가져 오지만 사용자 정의 구조체 MyCustomString은 사용하지 않으므로 완전히 일반적인 것은 아닙니다.
사샤

그리고 함수가 요소를 std :: string으로 예상하면 사용자가 std :: tuple <int, double, std :: nullptr_t>를 전달 하여 사용 및 유지 관리가 더 어려워집니다 .
사샤

@ 사샤 흠. 너의 의도를 알 겠어. 사실입니다. 고마워요!
theWiseBro
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.