c++ - How to eliminate cast for constructor selection -
i've been playing around generic mechanism converting value 1 set of values another, based on boost's map_list_of
template. 2 sets disjoint, it's not conversion 1 enumerated type another.
anyway, following code compiles , runs intended, i'm stuck on something. definition of enumtostring
, right before main()
, requires static_cast<const std::map<color, std::string> &>
cast. (fwiw, constructor causes convert()
function return key value string if cannot find key in map.) how can code compile without cast, while sticking c++03?
it might without cast there not enough type information available compiler figure out keytovalue
constructor call.
#include <sstream> #include <map> #include "boost/assign.hpp" template<typename k, typename v> // forward reference. class keytovalue; template<typename k, typename v> // k v (value or callback default). v convert(const keytovalue<k, v> &t, const k &k) { typename std::map<k, v>::const_iterator = t.m.find(k); return == t.m.end() ? (t.mc == null ? t.d : t.mc(k)) : it->second; } template<typename k> // k string (auto default). (use sfinae ostream&operator<<(k).) std::string convert(const keytovalue<k, std::string> &t, const k &k) { std::string v; typename std::map<k, std::string>::const_iterator = t.m.find(k); if (it == t.m.end()) if (t.auto_default) { std::ostringstream oss; oss << k; v = oss.str(); } else v = t.mc == null ? t.d : t.mc(k); else v = it->second; return v; } template<typename k, typename v> // construct conversion object convert(). class keytovalue { public: keytovalue(const std::map<k, std::string> &m) : // string w/auto default. m(m), d(v()), mc(null), auto_default(true) { } keytovalue(const std::map<k, v> &m, const v &d) : // v w/value default. m(m), d(d), mc(null), auto_default(false) { } keytovalue(const std::map<k, v> &m, v (*mc)(const k &)) : // callback. m(m), d(v()), mc(mc), auto_default(false) { } private: const std::map<k, v> m; const v d; // default value. v (*mc)(const k &); // callback returns default. const bool auto_default; // automatically create default key? template<typename k1, typename v1> friend v1 convert(const keytovalue<k1, v1> &t, const k1 &k); template<typename k1> friend std::string convert(const keytovalue<k1, std::string> &t, const k1 &k); }; #include <iostream> enum color { red, blue, orange, yellow, gold }; unsigned defaultunsigned(const color &myenum) { return -1; } const keytovalue<color, unsigned> enumtounsigned(boost::assign::map_list_of (orange, 13) (yellow, 58), defaultunsigned ); const keytovalue<color, std::string> enumtostring( static_cast<const std::map<color, std::string> &>(boost::assign::map_list_of (orange, "orange") (yellow, "yellow") ) ); int main() { std::cout << convert(enumtounsigned, yellow) << std::endl; std::cout << convert(enumtounsigned, gold) << std::endl; std::cout << convert(enumtostring, yellow) << std::endl; std::cout << convert(enumtostring, gold) << std::endl; }
this correct console output with cast:
58 4294967295 yellow 4
without cast, g++ (-std=c++98) generates these diagnostics:
prog.cc:64:43: error: call of overloaded 'keytovalue(boost::assign_detail::generic_list<std::pair<color, const char*> >&)' ambiguous (orange, "orange") (yellow, "yellow") ); ^ prog.cc:34:5: note: candidate: keytovalue<k, v>::keytovalue(const std::map<k, std::__cxx11::basic_string<char> >&) [with k = color; v = std::__cxx11::basic_string<char>] keytovalue(const std::map<k, std::string> &m) : // string w/auto default. ^ prog.cc:31:7: note: candidate: keytovalue<color, std::__cxx11::basic_string<char> >::keytovalue(const keytovalue<color, std::__cxx11::basic_string<char> >&) class keytovalue ^
update: here simplified version. how can rid of cast?
#include <map> #include "boost/assign.hpp" struct keytovalue { keytovalue(const std::map<int, bool> &m) { } } inttobool( static_cast<const std::map<int, bool> &>( boost::assign::map_list_of (3, true))); int main() { }
if understand design correctly, keytovalue
helper class doesn't need copied. ambiguity due copy ctor, need eliminate that. in c++11, you'd =delete
it. in c++03, make explicit
instead.
Comments
Post a Comment