为什么模板参数推导不起作用?

时间:2015-07-16 19:04:29

标签: c++ templates boost assign template-deduction

以下玩具程序将一种音乐转换为相应的颜色。它编译并执行得很好 - COUNTRY的转换失败,如预期的那样,conversion()函数返回默认值WHITE。但是,如果我删除模板参数<MUSIC, COLOR>,模板参数推断无法识别要使用的类型。如何才能获得演绎?

#include <map>
#include <iostream>
#include "boost/assign.hpp"

template<typename Key, typename T>
T convert(const Key &k, const T &d, const std::map<Key, T> &m) {
    typename std::map<Key, T>::const_iterator it = m.find(k);
    return it == m.end() ? d : it->second;
}

enum MUSIC { ROCK, RAP, EDM, COUNTRY };
enum COLOR { RED, BLUE, ORANGE, WHITE };

int main()
{
    COLOR c = convert<MUSIC, COLOR>(COUNTRY, WHITE,
        boost::assign::map_list_of (RAP, RED) (EDM, BLUE) (ROCK, RED));
    std::cout << c << std::endl;
}

2 个答案:

答案 0 :(得分:6)

boost::assign::map_list_of可能不属于map<K,V>类型,而是某种类型可转换为它。

编译器试图从前2个参数和最后1个参数中推断出类型。最后1个没有意义,所以它放弃了。

我们可以阻止对最后一个参数的推论如下:

template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;

template<class T>using block_deduction=type_t<tag<T>>;

template<typename Key, typename T>
T convert(const Key &k, const T &d, const block_deduction<std::map<Key, T>> &m) {
  typename std::map<Key, T>::const_iterator it = m.find(k);
  return it == m.end() ? d : it->second;
}

和鲍勃应该是你的叔叔。

在C ++ 03中:

template<class T>struct no_deduction{typedef T type;};

template<typename Key, typename T>
T convert(const Key &k, const T &d, const typename no_deduction<std::map<Key, T>>::type &m) {
  typename std::map<Key, T>::const_iterator it = m.find(k);
  return it == m.end() ? d : it->second;
}

这在逻辑上是等价的,但更加丑陋。

答案 1 :(得分:3)

Yakk boost::assign::map_list_of中的his answer提及不是std::map,而是可以转换为COLOR c = convert<MUSIC, COLOR>(COUNTRY, WHITE, boost::assign::map_list_of (RAP, RED) (EDM, BLUE) (ROCK, RED)); 。如果您不想更改功能,可以更改创建地图的方式。使用C ++,我们现在有initializer list可用于构造对象。使用初始化列表我们可以更改

COLOR c = convert(COUNTRY, WHITE, {{RAP, RED},{EDM, BLUE},{ROCK, RED}});

web.xml

这将使用相同的结果并允许模板类型扣除工作。

Live Example

相关问题