Как исключить приведение для выбора конструктора

Я играл с общим механизмом для преобразования значения из одного набора значений в другой, основанный на Boost’s map_list_of шаблон. Два набора в конечном итоге могут быть непересекающимися, так что это не просто преобразование одного перечислимого типа в другой.

В любом случае, следующий код компилируется и запускается, как задумано, но я застрял на чем-то. Определение enumToString, прямо перед main()требует static_cast<const std::map<COLOR, std::string> &> бросать. (FWIW, этот конструктор вызывает convert() функция для возврата значения ключа в виде строки, если он не может найти ключ на карте.) Как я могу получить код для компиляции без этого приведения, все время придерживаясь C ++ 03?

Может случиться так, что без приведения просто не хватит информации о типе, доступной для компилятора, чтобы выяснить, какие KeyToValue конструктор для вызова.

#include <sstream>
#include <map>
#include "boost/assign.hpp"
template<typename K, typename V> // Forward reference.
class KeyToValue;

template<typename K, typename V> // K to V (value or callback default).
V convert(const KeyToValue<K, V> &t, const K &k)
{
typename std::map<K, V>::const_iterator it = t.m.find(k);
return it == t.m.end() ? (t.mc == NULL ? t.d : t.mc(k)) : it->second;
}
template<typename K> // K to string (auto default). (Use SFINAE for 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 it = 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 for convert().
class KeyToValue
{
public:
KeyToValue(const std::map<K, std::string> &m) : // To string w/auto default.
m(m), d(V()), mc(NULL), auto_default(true) { }
KeyToValue(const std::map<K, V> &m, const V &d) : // To V w/value default.
m(m), d(d), mc(NULL), auto_default(false) { }
KeyToValue(const std::map<K, V> &m, V (*mc)(const K &)) : // with 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 that returns default.
const bool auto_default; // Automatically create default from 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;
}

Это правильный вывод консоли с В ролях:

58
4294967295
Yellow
4

Без приведения g ++ (-std = c ++ 98) генерирует эти диагностики:

prog.cc:64:43: error: call of overloaded 'KeyToValue(boost::assign_detail::generic_list<std::pair<COLOR, const char*> >&)' is 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) : // To 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
^

ОБНОВИТЬ: Вот упрощенная версия. Как я могу избавиться от актеров?

#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() { }

0

Решение

Если я правильно понимаю ваш дизайн, KeyToValue вспомогательный класс, который не нужно копировать Поскольку двусмысленность связана с копированием ctor, вы должны устранить это. В C ++ 11 вы просто =delete Это. В C ++ 03 сделайте это explicit вместо.

2

Другие решения