C++:使用类型作为映射键引入模板替换错误
C++: Using type as map key introduces template substitution errors
我使用元组作为键来跟踪地图中的元素,然后在地图上迭代以生成地图的字符串版本。为了帮助我进行转换,我有一个模板便利函数,它将连接用作键的元组(受 this answer 启发)。
#include <iostream>
#include <string>
#include <sstream>
#include <tuple>
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx == sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
}
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx < sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
if (idx != 0)
s << ",";
s << std::get<idx>(t);
cat_tuple<idx+1, T...>(t, s);
}
typedef std::tuple<int, int> my_tuple;
int main(){
my_tuple t(1, 2);
std::stringstream s;
cat_tuple(t, s);
std::cout << s.str() << std::endl; //Correctly prints "1,2"
}
我可以将元素插入地图并进行迭代而不会出错
#include <iostream>
#include <string>
#include <sstream>
#include <tuple>
#include <map>
typedef std::tuple<int, int> my_tuple;
typedef std::map<my_tuple, int> my_map;
int main(){
my_map m;
my_tuple t(1, 2);
m.insert(std::pair<my_tuple, int>(t, 1));
std::stringstream s;
for(my_map::iterator i = m.begin(); i != m.end(); ++i)
s << i->second;
std::cout << s.str() << std::endl; //Correctly prints "1"
}
但是当我尝试遍历地图时,出现替换错误:
#include <iostream>
#include <string>
#include <sstream>
#include <tuple>
#include <map>
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx == sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
}
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx < sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
if (idx != 0)
s << ",";
s << std::get<idx>(t);
cat_tuple<idx+1, T...>(t, s);
}
typedef std::tuple<int, int> my_tuple;
typedef std::map<my_tuple, int> my_map;
int main(){
my_map m;
my_tuple t(1, 2);
m.insert(std::pair<my_tuple, int>(t, 1));
std::stringstream s;
for(my_map::iterator i = m.begin(); i != m.end(); ++i){
if (i != m.begin())
s << "\n";
cat_tuple(i->first, s); //Substitution error, see below
s << " " << i->second;
}
std::cout << s.str() << std::endl;
}
生产(OSX 上的 g++ 4.2.1,删除了无关的 enable_if 注释)
$ g++ asdf.cc -std=c++11
asdf.cc:31:3: error: no matching function for call to 'cat_tuple'
cat_tuple(i->first, s); //Substitution error, see below
^~~~~~~~~
...
asdf.cc:14:1: note: candidate template ignored: substitution failure [with idx =
0, T = <int, int>]
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
^
1 error generated.
正如错误消息中所说,由于替换失败,我希望它使用的模板被忽略了。我把它移到地图上时引入了什么不同,我将如何纠正它?
将您的 cat_tuple
函数模板更改为
cat_tuple(std::tuple<T...> const& t, std::stringstream &s)
// ^^^^^
这是必要的,因为 std::map
的键是 const
。
无论如何,cat_tuple
的 tuple
参数应该是 const&
,因为它不会修改参数。
您可能希望将 cat_tuple
重命名为 tuple_printer
或类似名称,并将 std::stringstream
参数更改为 std::ostream
,这样您就可以将其传递给 std::cout
如果需要输出到 stdout
.
另外,现在的名字太让人联想到std::tuple_cat
。
我使用元组作为键来跟踪地图中的元素,然后在地图上迭代以生成地图的字符串版本。为了帮助我进行转换,我有一个模板便利函数,它将连接用作键的元组(受 this answer 启发)。
#include <iostream>
#include <string>
#include <sstream>
#include <tuple>
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx == sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
}
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx < sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
if (idx != 0)
s << ",";
s << std::get<idx>(t);
cat_tuple<idx+1, T...>(t, s);
}
typedef std::tuple<int, int> my_tuple;
int main(){
my_tuple t(1, 2);
std::stringstream s;
cat_tuple(t, s);
std::cout << s.str() << std::endl; //Correctly prints "1,2"
}
我可以将元素插入地图并进行迭代而不会出错
#include <iostream>
#include <string>
#include <sstream>
#include <tuple>
#include <map>
typedef std::tuple<int, int> my_tuple;
typedef std::map<my_tuple, int> my_map;
int main(){
my_map m;
my_tuple t(1, 2);
m.insert(std::pair<my_tuple, int>(t, 1));
std::stringstream s;
for(my_map::iterator i = m.begin(); i != m.end(); ++i)
s << i->second;
std::cout << s.str() << std::endl; //Correctly prints "1"
}
但是当我尝试遍历地图时,出现替换错误:
#include <iostream>
#include <string>
#include <sstream>
#include <tuple>
#include <map>
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx == sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
}
template<std::size_t idx = 0, typename ...T>
inline typename std::enable_if<idx < sizeof...(T), void>::type
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
if (idx != 0)
s << ",";
s << std::get<idx>(t);
cat_tuple<idx+1, T...>(t, s);
}
typedef std::tuple<int, int> my_tuple;
typedef std::map<my_tuple, int> my_map;
int main(){
my_map m;
my_tuple t(1, 2);
m.insert(std::pair<my_tuple, int>(t, 1));
std::stringstream s;
for(my_map::iterator i = m.begin(); i != m.end(); ++i){
if (i != m.begin())
s << "\n";
cat_tuple(i->first, s); //Substitution error, see below
s << " " << i->second;
}
std::cout << s.str() << std::endl;
}
生产(OSX 上的 g++ 4.2.1,删除了无关的 enable_if 注释)
$ g++ asdf.cc -std=c++11
asdf.cc:31:3: error: no matching function for call to 'cat_tuple'
cat_tuple(i->first, s); //Substitution error, see below
^~~~~~~~~
...
asdf.cc:14:1: note: candidate template ignored: substitution failure [with idx =
0, T = <int, int>]
cat_tuple(std::tuple<T...> &t, std::stringstream &s){
^
1 error generated.
正如错误消息中所说,由于替换失败,我希望它使用的模板被忽略了。我把它移到地图上时引入了什么不同,我将如何纠正它?
将您的 cat_tuple
函数模板更改为
cat_tuple(std::tuple<T...> const& t, std::stringstream &s)
// ^^^^^
这是必要的,因为 std::map
的键是 const
。
无论如何,cat_tuple
的 tuple
参数应该是 const&
,因为它不会修改参数。
您可能希望将 cat_tuple
重命名为 tuple_printer
或类似名称,并将 std::stringstream
参数更改为 std::ostream
,这样您就可以将其传递给 std::cout
如果需要输出到 stdout
.
另外,现在的名字太让人联想到std::tuple_cat
。