C++, template 초보질문 드립니다. 조언 좀 부탁드려요...

tien770의 이미지

여러가지 형태의 데이터를 저장하려고 이런 클래스를 사용하고 있습니다.
질문에 필요한 부분만으로 단순화시켰습니다.

class MyData
{
public:
	void Push(int data) { IntData.push_back(data); }
	void Push(float data) { FloatData.push_back(data); }
	void Push(string data) { StringData.push_back(data); }
 
	vector<int>		IntData;
	vector<float>	FloatData;
	vector<string>	StringData;
};

그런데 필요한 type마다 다 저렇게 만들어주는건 비효율적인것 같아서 template을 쓰려고 시도하였습니다.

class MyData2
{
public:
 
	// 1. 이렇게 만들고 싶었는데, XXX부분을 어떻게 써야 할지 모르겠습니다.
	template<typename T>
		void Push1(T data) { XXX.push_back(data); }
 
	// 2. 그래서 이렇게 시도를 해 보았는데, 컴파일러가 메시지박스 보이고 죽어버립니다 ㅠㅠ
	template<typename T>
		void Push2(T data) { Data<T>.push_back(data); }
	template<typename T>	
		vector<T>	Data;
 
	// 3. 결국 이 방법으로 성공은 했습니다만...
	template<typename T>
		void Push3(T data) { Container<T>().push_back(data); }
	template<typename T>
		vector<T> &Container(void) { static vector<T> v; return v; }
 
	// 4. 모든 data를 다 뒤지려면 비슷한 문제가 다시 발생합니다. 게다가, 빼먹는 data가 분명 생길테구요.
	void Save2File()
	{
		Save(Container<int>());
		Save(Container<float>());
		Save(Container<string>());
	}
	template<typename T>
	void Save(const vector<T> &c) const { c; }
};

결국 대안은 없는 것일까요.
저것 때문에 덩치큰 데이터관리 모듈을 만들기는 배꼽이 더 큰거 같고
분명 명쾌하고 간단한 실마리가 있을거 같은데... 감을 못 잡겠네요.

조언 좀 부탁드립니다.

towstock의 이미지

템플릿 함수 대신 아래처럼 템플릿 클래스를 사용하시면 됩니다.

template
class MyData
{
void Push(T data) { Storage.push_back( data ); }
vector Storage;
};

tien770의 이미지

함수가 템플릿이든 클래스가 템플릿이든 마찬가지 아닌가요?

여기저기에서 Push를 사용할 경우에, 나중에 모든 데이터를 다 찾아내려면
사용된 모든 타입들을 다 기억하지 않는한
일부 데이터를 빠트리게 되는 상황이 말이죠.

답변 주신 내용은 2번 항목까지에 해당하는 것 같은데요.

growingdever의 이미지

아이템 부분을 구현하시려는 것이 아닐까 싶은데요.

아이템이라는 클래스를 만들어 모든 아이템에서 필요한 부분을 최상위 클래스에서 구현해놓는거죠.

익명 사용자의 이미지

템플릿을 사용해서 사용자가 명시적으로 클래스를 인스턴스화 할 때 쓰겠다는 것이 아니라.
예) MyClass 이런것 없이..
코드상에서 사용자 마음데로 아무 자료형이나 push를 하고 컴파일러가 알아서 그것들을 종합해서 "이 클래스는 이러한 자료형들을 필요로 해"
라고 하고 싶으신거죠? - 그렇다면 쉽지 않아보입니다만..

어차피 기존의 프로그래밍 방법 자체가 각 필요한 자료형에 대한 vector를 클래스에 일일이 선언하시는 거라면
그러면 선언하실때 MyClass<필요한 타입들..> 만 하시면 원하시는 기능을 구현하실 수는 있습니다.

다만 C++11 에서 제공하는 Variadic Template이 필요하죠.

만약 C++11이 불가능하시다면 아쉬운데로 tuple을 이용해서 어느정도 흉내는 낼 수 있습니다만 이 또한
템플릿 갯수별로 setter와 getter를 또 만들어주셔야 합니다. (좀 많이 길어집니다만 하나 만들어두면 두고두고 사용하실 수는 있겠지요.)

익명 사용자의 이미지

참고하시면 될 듯 합니다.

#include <iostream>
#include <typeinfo>
#include <boost/utility.hpp>
#include <boost/type_traits.hpp>
#include <vector>
 
class Nil {
};
 
template <typename Current, typename Next>
class Tuple {
};
 
class my_visitor {
	public:
	template <typename T>
	void operator()(T & v) {
		std::cout << v << std::endl;
	}
};
 
template <typename Types>
class MyData;
 
template <>
class MyData<Nil> {
	public:
	template <typename Visitor>
	void forall(Visitor &) {
	}
};
 
template <typename Current, typename Next>
class MyData<Tuple<Current, Next> > : public MyData<Next> {
	typedef MyData<Next> p_t;
	std::vector<Current> items;
 
	public:
	template <typename T>
	void push(T a, typename boost::enable_if<boost::is_same<T, Current> >::type * = 0) {
		items.push_back(a);
	}
	template <typename T>
	void push(T a, typename boost::disable_if<boost::is_same<T, Current> >::type * = 0) {
		p_t::push(a);
	}
	template <typename Visitor>
	void forall(Visitor & v) {
		for (size_t i = 0; i < items.size(); ++i) v(items[i]);
		p_t::forall(v);
	}
};
 
int main() {
	MyData<Tuple<int, Tuple<char , Nil> > > a;
	a.push(42);
	a.push('a');
	my_visitor v;
	a.forall(v);
	return 0;
}
익명 사용자의 이미지

출처 기입을 깜빡했네요. 연구실에 학부 연구생이 있는데 그친구가 짰습니다. https://github.com/Mortal/varvector

tien770의 이미지

코드를 딱 보기만 해도, 공부하기 참 좋다는 생각이 듭니다.
최근에서야 boost를 설치했기에, 아직 boost::enable_if 같은거에 익숙하지는 않지만
바로 감이 잡히네요.

처음에 컨테이너를 만들때에 미리 예상 타입들을 다 열거해 놓아야 한다는거 말고는 정말 만능이라고 여겨집니다.
요즘 공부하고 있는 Typelist가 딱 떠오르네요.
좋은 공부되게 해 주셔서 감사합니다.

HDNua의 이미지

Objective-C의 Foundation 프레임워크에 있는 NSMutableArray에서 영감을 얻어
C++ 스타일로 새롭게 작성해봤습니다.
만들어놓은 파일이 많아 압축 파일로 올려볼게요.
아직 구현이 덜 된 부분도 있지만 제법 괜찮게 동작하는 것 같군요.

최상위 객체가 있으면 이렇게 편리하게 다룰 수 있습니다..는 정도만 보시면 될 것 같습니다.

댓글 첨부 파일: 
첨부파일 크기
Package icon Archive.zip11.59 KB

저는 이렇게 생각했습니다.

tien770의 이미지

템플릿이 아니라 클래스 계승을 통해 구성하셨네요.
방향전환이 참신하다고 생각했습니다.

다만 현재 올려주신 소스로는 addObject한 객체가 스코프 벗어나서 소멸되면
문제가 발생하는 구조이기 때문에 그 부분만 조금 손보면
훌륭한 방법이 될 수 있을거라 생각됩니다.

그리고 HDObject 객체를 미리 만들어서 넣는 것보다는
addObject를 템플릿 함수로 만들고,
거기에서 변환을 해서 집어넣어주는게 사용상에는 편리할 듯 싶습니다.

좋은 아이디어 주셔서 감사합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.