如何消除构造函数选择的强制转换

时间:2015-07-24 00:18:35

标签: c++ templates boost casting ambiguous-call

我一直在使用通用机制,根据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;
}

这是正确的控制台输出 with cast:

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

1 个答案:

答案 0 :(得分:2)

如果我正确理解您的设计,KeyToValue是一个不需要复制的辅助类。由于模糊是由于复制ctor,你需要消除它。在C ++ 11中,你只需=delete它。在C ++ 03中,改为explicit