2014-06-22 2 views
2

가변적 인 수의 템플릿 화 된 인수가있는 템플릿 화 된 클래스가 있습니다. 이 경우 (나는 C++ 11을 가질 여유가 없다), 좋은 연습은 none이라고 부르는 기본 클래스를 생성하고 아래와 같이 기본값으로 두는 것이다.가변 수의 템플릿 화 된 인수로 템플릿 화 된 클래스의 멤버에 액세스

struct none {}; 

template<class T1=none, T2=none, T3=none> 
class A{ 

    template<class T> 
    double extract() { return none();} 

    template<> 
    double extract<T1>() { return m1_();} 

    template<> 
    double extract<T2>() { return m2_();} 

    template<> 
    double extract<T3>() { return m3_();} 

    T1 m1_; 
    T2 m2_; 
    T3 m3_; 
}; 

이 단계에서는 템플릿 된 인수 각각에 액세스 할 수있는 일반/템플릿 액세스 함수를 구현하는 방법을 알지 못합니다.

템플릿 기반 인수가 모두 다르기 때문에 템플릿 기반 인수 각각에 대해 A :: extract()를 특수화했습니다.

더 좋은 방법이 있습니까? 어떤 종류의 태깅이라도 볼 수 있나요?

+0

'T1'과 'T2'가 같은 유형 인 경우이 액세스 방법은 모호 해집니다. –

+0

이것은 [is_same] (http://en.cppreference.com/w/cpp/types/is_same)의 이점이 될 것입니다. –

+3

boost :: tuples 사용 http://www.boost.org/doc/libs /1_55_0/libs/tuple/doc/tuple_users_guide.html –

답변

0
struct none {}; 

template <class T, class N> 
class Holder : public N 
{ 
    protected: 
    T m; 
    typedef Holder<T, N> First; 
    double extractP(T*) { return m(); } 
    template <class X> double extractP(X*) { 
     return this->N::extractP(static_cast<X*>(0)); 
    } 
}; 

template <class T> 
class Holder<T, none> 
{ 
    protected: 
    T m; 
    typedef Holder<T, none> First; 
    double extractP(T*) { return m(); } 
    template <class X> none extractP(X*) { 
     return none(); 
    } 
}; 



template <class T1 = none, class T2 = none, class T3 = none> 
class A : Holder<T1, Holder<T2, Holder<T3, none> > > 
{ 
    public: 
    template <class T> double extract() { 
     return this->extractP(static_cast<T*>(0)); 
    } 
}; 
0

비슷한 이름의 솔루션은 n.m하지만 부스트의 Variant 클래스 디자인에 대한 자세한합니다.

Variant 컨테이너 (개체의 일반 컨테이너)를 사용하고 직접 접근자를 사용하는 것이 좋습니다.

#include <iostream> 
#include <stdexcept> 
using namespace std; 


class BaseHolder 
{ 
public: 
    virtual ~BaseHolder(){} 
    virtual BaseHolder* clone() const = 0; 
}; 

template<typename T> 
class HoldData : public BaseHolder 
{ 
public: 
    HoldData(const T& t_) : t(t_){} 

    virtual BaseHolder* clone() const { 
    return new HoldData<T>(t); 
    } 

    T getData() { 
     return t; 
    } 

private: 
    T t; 
}; 


class Variant 
{ 
public: 

    Variant() : data(0) {} 

    template<typename T> 
    Variant(const T& t) : data(new HoldData<T>(t)){} 

    Variant(const Variant& other) : data(other.data ? other.data->clone() : 0) {} 
    ~Variant(){delete data;} 

    template<typename T> 
    T getData() { 
     return ((HoldData<T>*)data)->getData(); 
    } 

private: 
    BaseHolder* data; 

private: 
    Variant& operator=(const Variant& other) { return *this;} // Not allowed 
}; 

struct none {}; 

class Container{ 
public: 
    Container() : m1_(0), m2_(0), m3_(0){} 
    ~Container() { 
     if(m1_) 
      delete m1_; 
     if(m2_) 
      delete m1_; 
     if(m3_) 
      delete m1_; 
    } 

    none extract() { return none();} 

    template<typename T> 
    void insertM1(T obj) { 
     m1_ = new Variant(obj); 
    } 

    template<typename T> 
    T extractM1() { 
     if(m1_ != 0) 
      return m1_->getData<T>(); 
     else 
      throw std::runtime_error("Element not set"); 
    } 

    // TODO: implement m2 and m3 

    Variant *m1_; 
    Variant *m2_; 
    Variant *m3_; 
}; 

int main() { 

    Container obj; 

    char M1 = 'Z'; 
    obj.insertM1(M1); 

    char extractedM1 = obj.extractM1<char>(); 
    cout << extractedM1; 

    return 0; 
} 

http://ideone.com/BaCWSV

0

클래스는 불행하게도 당신을 위해, C++ 11에 추가 된, std::tuple을 모방하는 것 같다. 좋은 소식은 대신 boost::tuple을 사용할 수 있다는 것입니다. 사용의 예로서

:

boost::tuple<std::string, double> t = boost::make_tuple("John Doe", 4.815162342); 
std::cout << boost::get<0>(t) << '\n'; 
std::cout << boost::get<1>(t) << '\n'; 
C++ (11)에 액세스하지 않고

Live demo

+0

이것은 유형별이 아닌 색인 별 액세스입니다. –

+0

@MatthieuM. 유형은 컴파일 시점에서 고정되어 있으므로 유형별로 색인화됩니다. – Shoe

+0

작동 여부와 사용자에게 드러내고 싶은 인터페이스의 문제가 덜 중요합니다. 인덱스를 노출하면 맵핑 인덱스 <->이 약간 다루기 힘든 것을 항상 기억해야합니다. –

0

, 그것은 조금 이보다하지만 당신은 Boost.Tuple 활용할 수 있습니다 :

#include <iostream> 
#include <boost/tuple/tuple.hpp> 

template <size_t I, typename T, typename U> 
struct AccessImpl; 

template <size_t I, typename T, typename U> 
struct AccessImpl { 
    template <typename Tuple> 
    static T& impl(Tuple& tuple) { 
     typedef typename ::boost::tuples::element<I+1, Tuple>::type Next; 
     return AccessImpl<I+1, T, Next>::impl(tuple); 
    } 
}; 

template <size_t I, typename T> 
struct AccessImpl<I, T, T> { 
    template <typename Tuple> 
    static T& impl(Tuple& tuple) { return boost::get<I>(tuple); } 
}; 

template <typename T, typename Tuple> 
T& access(Tuple& tuple) { 
    typedef typename ::boost::tuples::element<0, Tuple>::type Head; 
    return AccessImpl<0, T, Head>::impl(tuple); 
} 

int main() { 
    boost::tuples::tuple<char, int, std::string> example('a', 1, "Hello, World!"); 
    std::cout << access<std::string>(example) << "\n"; 
    return 0; 
} 

을 예상대로, prints "Hello, World!"입니다.