2011-01-02 3 views
4

Я пытаюсь написать функцию перевода, которая принимает значение и серию поисковых таблиц в качестве аргументов. таблица перекодировки имеет следующее заявление:C++ template function question

template< typename fromType, typename toType> struct DataTranslator; 

я могу заставить его работать со следующими перевести объявления функций шаблона:

template< typename Return, typename Direction, typename ValType, typename TransType> 
Return translate(ValType val, TransType& trans); 

template< typename Return, typename Direction, typename ValType, typename TransType, typename... OtherTrans> 
Return translate(ValType val, TransType& trans, OtherTrans&... others); 

Затем я могу сделать что-то вроде следующего:

DataTranslator<specificBaud, universalBaud>::type baudTranslator; 
DataTranslator<universalBaud, std::string>::type baudCmdTranslator; 

specificBaud myBaud; 
.... 
std::string result = translate<std::string, forward_trans>(myBaud, baudTranslator, baudCmdTranslator); 

, но если я изменю декларацию своих функций перевода на:

template< typename Return, typename Direction, typename ValType, typename FT, typename TT> 
Return translate(ValType val, typename DataTranslator<FT, TT>::type& trans); 

template< typename Return, typename Direction, typename ValType, typename FT, typename TT, typename... OtherTrans> 
Return translate(ValType val, typename DataTranslator<FT, TT>::type& trans, OtherTrans&... others); 

При выполнении переводимого вызова я получаю не соответствующую ошибку вызова функции. Я использую GCC 4.5 для моего компилятора с флагом -std = C++ 0x.

Мой главный вопрос: почему вторая версия не работает? Я видел примеры (в основном класс Tuple, выдвинутый в одном из предложений для варидических шаблонов), где они делают этот тип разложения типа для его специализации.

Полный код теста:

/* 
* bimap_test.cpp 
* 
* Created on: Dec 27, 2010 
*  Author: natejohn 
*/ 

#include <iostream> 
#include <utility> 
#include <string> 
#include <boost/multi_index_container.hpp> 
#include <boost/multi_index/ordered_index.hpp> 
#include <boost/multi_index/member.hpp> 
#include <boost/multi_index/tag.hpp> 
#include <boost/mpl/if.hpp> 
#include <boost/function.hpp> 
#include <tr1/type_traits> 

enum silly {car, boat, plane, truck}; 
enum furry {bunny, dog, cat, donkey, critter}; 

struct forward_trans {}; 
struct reverse_trans {}; 

template<typename from, typename to> struct DataTranslator 
{ 
    typedef std::pair<from, to> Element; 
    typedef boost::multi_index_container<Element, boost::multi_index::indexed_by< 
      boost::multi_index::ordered_unique< 
      boost::multi_index::tag<forward_trans>, 
      boost::multi_index::member<Element, typename Element::first_type,  &Element::first> 
      >, 
      boost::multi_index::ordered_unique< 
     boost::multi_index::tag<reverse_trans>, 
     boost::multi_index::member<Element, typename Element::second_type, &Element::second> 
     > 
     > 
> type; 

    // Added after Answer accepted as what I fixed to get this to work 
    type trans; 


}; 

template<typename R, typename I> struct forward_extractor 
{ 
    R operator()(I it) { return it->second; } 
}; 

template<typename R, typename I> struct reverse_extractor 
{ 
    R operator()(I it) { return it->first; } 
}; 

template<typename from, typename to> struct FunctionTranslator 
{ 
    typedef boost::function<to (from) > forward_type; 
    typedef boost::function<from (to) > reverse_type; 
}; 

/*template<typename R, typename D, typename V, typename Trans> 
R translate(V v, Trans& t); 

template<typename R, typename D, typename V, typename Trans, typename... Others> 
R translate(V v, Trans& t, Others&... o); 
*/ 

template<typename R, typename D, typename V, typename FT, typename TT, typename...  others> 
R translate(V val, boost::function<TT(FT)> trans, others&... o) 
{ 
    TT temp = trans(val); 
    return static_cast<R>(translate<R, D>(temp, o...)); 
} 

template<typename R, typename D, typename V, typename FT, typename TT> 
R translate(V val, boost::function<TT(FT)>& func) 
{ 
    return static_cast<R>(func(val)); 
} 

template<typename R, typename D, typename V, typename FT, typename TT> 
R translate(V val, typename DataTranslator<FT, TT>::type& trans) 
{ 
    typedef typename DataTranslator<FT, TT>::type::template index<D>::type lookup_table; 
    typedef typename lookup_table::iterator lut_iterator; 
    lookup_table& lut = boost::multi_index::get<D>(trans); 

R not_found; 

typedef typename boost::mpl::if_c<std::tr1::is_same<D, forward_trans>::value, forward_extractor<TT, lut_iterator>, 
      typename boost::mpl::if_c<std::tr1::is_same<D, reverse_trans>::value, reverse_extractor<FT, lut_iterator>, bool>::type>::type extractor_type; 

extractor_type ext; 

lut_iterator it = lut.find(val); 

if(it == lut.end()) 
{ 
    return not_found; 
} 

return static_cast<R>(ext(it)); 

} 


template<typename R, typename D, typename V, typename FT, typename TT, typename... others> 
R translate(V val, typename DataTranslator<FT, TT>::type& trans, others&... o) 
{ 
typedef typename DataTranslator<FT, TT>::type::template index<D>::type lookup_table; 
typedef typename lookup_table::iterator lut_iterator; 
lookup_table& lut = boost::multi_index::get<D>(trans); 
R not_found; 
typedef typename boost::mpl::if_c<std::tr1::is_same<D, forward_trans>::value, forward_extractor<TT, lut_iterator>, 
      typename boost::mpl::if_c<std::tr1::is_same<D, reverse_trans>::value, reverse_extractor<FT, lut_iterator>, bool>::type >::type extractor_type; 
extractor_type ext; 


lut_iterator it = lut.find(val); 

if(it == lut.end()) 
{ 
    return not_found; 
} 

return translate<R, D>(ext(it), o...); 

} 


int main(int argc, char** argv) 
{ 
typedef typename DataTranslator<silly, furry>::type SillyToFurryTranslatorType; 
typedef typename DataTranslator<furry, std::string>::type FurryToStringTranslatorType; 


DataTranslator<silly, furry>::type stft; 
DataTranslator<furry, std::string>::type ftst; 

stft.insert(std::make_pair(car, dog)); 
stft.insert(std::make_pair(boat, cat)); 
ftst.insert(std::make_pair(dog, "Doggie!")); 
ftst.insert(std::make_pair(cat, "Earl the Dead Cat")); 

std::string result = translate<furry, forward_trans>(car, stft, ftst); 
std::cout << result << std::endl; 

return 0; 
} 

+1

Почему тип :: type во втором типе аргументов? Вы пытались использовать 'translate (ValType val, DataTranslator & trans)'? –

+0

Вы вызывали вторую функцию с 'translate (myBaud, baudTranslator, baudCmdTranslator)'? – chrisaycock

+0

@Giuseppe Ottaviano: :: type - это потому, что структура DataTranslator используется только для сохранения ввода. это пара typedefs, первая для std :: pair, вторая для boost :: multi_index_container. Тип :: type - для multi_index_container. В конечном итоге у меня будет только более 100 этих таблиц поиска в проекте, и поэтому я считаю, что typedefs, предоставляемые структурой DataTranslator, сохраняют около 1000 строк повторяющегося кода. – diverscuba23

ответ

4

Я думаю, что проблема в том, что C++ шаблона вывод аргумент ломается, если вы попытаетесь вывести тип внешнего класса от типа некоторого типа вложенного если оно. Например, это не будет работать правильно:

template <typename T> void DoSomething(typename std::vector<T>::iterator itr); 

std::vector<int> v; 
DoSomething(v.begin()); 

Причина этого заключается в том, что компилятор не может однозначно определить, какой внешний вид должен быть во всех случаях. Например, рассмотрим следующий случай:

template <typename T> class Pathological { 
     typedef int type; 
}; 

template <typename T> void WhatIsT(typename Pathological<T>::type huh); 

Проблема здесь состоит в том, что каждый конкретизации патологической имеет тот же тип, указанный для его типа типа. Следовательно, если вы должны были передать Pathological<int>::type или Pathological<double>::type, компилятор не смог определить, что такое внешний тип, потому что оба эти типа оценивают значение int.

Надеюсь, это поможет!

+0

Спасибо. Это была моя проблема. – diverscuba23