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

3
下面这个玩具程序将音乐类型转换为相应的颜色。它可以编译并正常执行——如预期般,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;
}

如果您也为 map 类型添加一个模板参数会发生什么? - jxh
根据@jxh的建议,模板<template<typename, typename> Map, typename Key, typename Value> > ...? - mrtimdog
2个回答

6
boost::assign::map_list_of 可能不是类型 map<K,V>,而是可以转换为该类型的某种类型。
编译器试图从前两个参数和最后一个参数中推断出类型。但最后一个参数没有意义,因此编译器放弃了推断。
我们可以按以下方式阻止对最后一个参数的推断:
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;
}

And Bob 应该是你的叔叔。
在 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;
}

这个表达虽然逻辑上等价,但更加丑陋。


确实,这是一个 assign_detail::generic_list<std::pair<...>> - Barry
1
coliru显示:'boost :: assign_detail :: generic_list <std :: pair <MUSIC,COLOR>>'不是派生自'const std :: map <Key,T>' boost :: assign :: map_list_of(RAP,RED)(EDM,BLUE)(ROCK,RED)); - NathanOliver
3
@Barry aka,"auto"的产生原因。 - Yakk - Adam Nevraumont
1
@Yakk 当然。只是为了确认你的第一句话(好像你需要它一样)。 - Barry
@Yakk @NathanOliver 哦,忘了说我想要一个C++03的解决方案,所以auto和初始化列表都不行。 - plong
显示剩余3条评论

3

正如Yakk他的回答中所提到的那样,boost::assign::map_list_of并不是std::map,但它可以转换为一个std::map。如果不想改变您的函数,您可以改变创建映射的方式。使用C ++,我们现在有initializer list,可用于构造对象。使用初始化列表,我们可以改变。

COLOR c = convert<MUSIC, COLOR>(COUNTRY, WHITE,
    boost::assign::map_list_of (RAP, RED) (EDM, BLUE) (ROCK, RED));

To

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

使用此方法将得到相同的结果,同时允许模板类型推导起作用。

实时示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接