C++ template function question
I am trying to write a translation function that takes the value and the series of lookup tables as arguments. the lookup table has the following declaration:
template< typename fromType, typename toType> struct DataTranslator;
I can get it to work with the following translate template function declarations:
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);
I can then do something like the following:
DataTranslator<specificBaud, universalBaud>::type baudTranslator;
DataTranslator<universalBaud, std::string>::type baudCmdTranslator;
specificBaud myBaud;
....
std::string result = translate<std::string, forward_trans>(myBaud, baudTranslator, baudCmdTranslator);
but if I change the declaration of my translate functions to:
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);
I get a no matching function call error when making the translate call. I'm using GCC 4.5 for my compiler with the -std=c++0x flag.
My main question is why does the second version not work? I have seen examples (mainly a Tuple class put forward in one of the proposals for varidic templates) where they do that type of decomposition of a type to specialize it.
Complete Test code:
/*
* 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;
}
I think the problem is that C++ template argument deduction breaks down if you try to deduce the type of an outer class from the type of some type nested inside if it. For example, this won't work correctly:
template <typename T> void DoSomething(typename std::vector<T>::iterator itr);
std::vector<int> v;
DoSomething(v.begin());
The reason for this is that the compiler can't unambiguously determine what the outer type must be in all cases. For example, consider this case:
template <typename T> class Pathological {
typedef int type;
};
template <typename T> void WhatIsT(typename Pathological<T>::type huh);
The problem here is that every instantiation of Pathological has the same type specified for its type type. Consequently, if you were to pass in a Pathological<int>::type
or a Pathological<double>::type
, the compiler couldn't determine what the outer type was because both of those types evaluate to int.
Hope this helps!
精彩评论