2015-07-24 1 views
0

Я играл с универсальным механизмом для преобразования значения из одного набора значений в другой, основываясь на шаблоне Boost 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() { } 

ответ

2

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

+0

Я пробовал «явный», но это не помогло. Пожалуйста, взгляните на гораздо более простую версию кода, который я добавил как UPDATE внизу моего исходного запроса. – plong