为什么模板参数推导不起作用?
Why isn't template argument deduction working?
以下玩具程序将一种音乐转换为相应的颜色。它编译和执行得很好——COUNTRY
的转换如预期的那样失败,conversion()
函数 returns 是默认值,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;
}
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;
}
这在逻辑上是等价的,但更丑陋。
As Yakk mentions in boost::assign::map_list_of
is not std::map
but it is convertible to one. If don't wan't to change your function you can change how you create the map. With C++ we now have initializer list 可用于构造对象。使用初始化列表我们可以改变
COLOR c = convert<MUSIC, COLOR>(COUNTRY, WHITE,
boost::assign::map_list_of (RAP, RED) (EDM, BLUE) (ROCK, RED));
到
COLOR c = convert(COUNTRY, WHITE, {{RAP, RED},{EDM, BLUE},{ROCK, RED}});
这将给出相同的结果并允许模板类型推导工作。
以下玩具程序将一种音乐转换为相应的颜色。它编译和执行得很好——COUNTRY
的转换如预期的那样失败,conversion()
函数 returns 是默认值,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;
}
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;
}
这在逻辑上是等价的,但更丑陋。
As Yakk mentions in boost::assign::map_list_of
is not std::map
but it is convertible to one. If don't wan't to change your function you can change how you create the map. With C++ we now have initializer list 可用于构造对象。使用初始化列表我们可以改变
COLOR c = convert<MUSIC, COLOR>(COUNTRY, WHITE,
boost::assign::map_list_of (RAP, RED) (EDM, BLUE) (ROCK, RED));
到
COLOR c = convert(COUNTRY, WHITE, {{RAP, RED},{EDM, BLUE},{ROCK, RED}});
这将给出相同的结果并允许模板类型推导工作。