std::unordered_mapやstd::mapの比較用のファンクタとしてラムダ式を渡す

やろうとして意外に面倒だった。が、だれも書いていないみたいなので書いておく。より面倒なのはstd::unordered_mapのほうなのでこちらについて主に書く。

面倒なのは基本的にテンプレート引数としてファンクタを渡す仕様になっているということ。ラムダ式は型ではないので当然テンプレート引数として渡すことができない。しかも、デフォルトの型というのがラムダ式を受け取れるような型ではない(std::equal_to)になっているのでコンストラクタにそのまま渡すということができない。そこでstd::funcでラムダ式を受け取れるようにテンプレートパラメータを変更しなくてはいけない。ただ、その前にハッシュ関数のファンクタを指定するテンプレートパラメータがあるのでそれはデフォルトにしてとかやる必要がある。

あれこれいっててもわかりにくいと思うのでサンプルをあげておく。これをみればわかるようにとある事情でstd::stringではなくconst char*をキーにしたかったわけだがその比較のためにファンクタをわたす必要があった。

#include<iostream>
#include<unordered_map>
#include<functional>


int main(){

	std::unordered_map<const char*, const char*,std::hash<const char*>,std::function<bool(const char*, const char*)> > Map
	(
		0,
		std::hash<const char*>(),
		[](const char* lhs,const char* rhs){return (strcmp(lhs, rhs) == 0)? true : false;}
	) ;


	Map["hoge"]="aa";
	Map["bar"]="ab";

	std::cout<< Map["bar"] << std::endl;
	std::cout<< Map["hoge"] << std::endl;


	return 0;
}

std::mapのほうはハッシュ関数を指定しなくていいので多少楽だ。第三テンプレート引数にstd::functionを指定するだけで普通に渡せるようになる。

#include<iostream>
#include<functional>
#include<map>

int main(){

	std::map<const char*, const char*,std::function<bool(const char*, const char*)> > Map(
		[](const char* lhs,const char* rhs){return (strcmp(lhs, rhs) == 0)? true : false;}
	);


	Map["hoge"]="aa";
	Map["bar"]="ab";

	std::cout<< Map["bar"] << std::endl;


	return 0;
}

たぶん、ラムダ式が存在しない時代はテンプレートで指定できるほうが便利だったのだろう。しかし今となっては逆に面倒だ。せめてstd::function >をデフォルトテンプレート引数にしてよかったと思うのだが、ここら辺は下位互換の問題なのだろうか?...