Explicit conversion and templated conversion opera

2019-07-27 01:58发布

问题:

I wanted to somehow extend the Microsoft type _variant_t so it accepts implicit/explicit conversions to/from additional types. To do so, I wrote the following class:

class value_type
{
  public:
    /* Constructors */
    value_type(const std::string& str) : m_variant(str.c_str()) {}
    template <typename Type> value_type(const Type& value) : m_variant(value) {}

    /* Conversion operators */
    operator const _variant_t&() const { return m_variant; }
    operator std::string() const { return static_cast<const char*>(m_variant); }
    template <typename Type> operator Type() const { return static_cast<Type>(m_variant); }
  private:
    _variant_t m_variant;
};

That is, if every instance of _variant_t in the code is replaced with value_type, it "works" the same.

Lets consider the following function, which returns a _variant_t:

_variant_t foo();

If I write:

std::string bar()
{
  value_type v = foo();
  return v;
}

It compiles just fine.

But if I change the previous code like that:

std::string bar()
{
  return value_type(foo());
}

or:

std::string bar()
{
  return static_cast<std::string>(value_type(foo()));
}

The compilation fails with the following message:

configuration.cpp(41) : error C2668: 'std::basic_string<_Elem,_Traits,_Ax>::basic_string' : ambiguous call to overloaded function

If I remove the template <typename Type> operator Type... line, everything compiles.

Now I understand what the compilater says (it doesn't know which operator to use) but I don't understand why: It would seem logical to use the operator std::string when converting to std::string. What am I missing ?

Thank you.

回答1:

The problem is that string's constructor is overloaded. So if returning involves invoking a string constructor, then there are multiple choices: argument could be converted to const char*, allocator<char> or string.

static_cast<string>(x) is the same as string(x).

I suppose your first faulty example should read return string(foo());, not return value_type(foo());