简体   繁体   中英

How does operator overload resolution work in the presence of the new initializer sequence?

Given the following code:

#include <iostream>
#include <vector>

template <typename Source>
class ConvertProxy
{
    Source const* m_source;
public:
    ConvertProxy( Source const& source )
        : m_source( &source )
    {
    }

    template <typename Dest>
    operator Dest() const
    {
        return Dest(m_source->begin(), m_source->end());
    }
};

template <typename Source>
ConvertProxy<Source> convert( Source const& source )
{
    return ConvertProxy<Source>( source );
}

int
main()
{
    std::vector<int> src;
    for ( int i = 0; i != 5; ++ i ) {
        src.push_back( i );
    }
    std::vector<double> dest = convert( src );   /* XXX */
    for ( std::vector<double>::const_iterator i = dest.begin(), e = dest.end();
            i != e;
            ++ i ) {
        std::cout << *i << std::endl;
    }
    return 0;
}

is this legal in C++11, or is the line marked XXX ambiguous?

The same question, but with the marked line replaced by:

std::vector<double> dest( convert( src ) );

or with

std::vector<double> dest;
dest = convert( src );

In pre-C++11, I think the second was illegal, but the other two definitely were not.

FWIW: g++ (4.8.2) accepts the first, but not the other two (with -std=c++11 ; otherwise it accepts the first and the third, but not the second). VS 2013 accepts all of them, but Intellisense marks all of them are erroneous (which is what triggered my interest: you get a nice red marking in the scrollbar, with symbols underlined in red, but the code compiles perfectly). In other words: three compilers, and three different behaviors.

(And for those who wonder as to why: this is a standard idiom for getting the context—the left hand side of an assignment, for example—involved in overload resolution.)

There is ambiguity on the side of the compiled code that must be resolved first, and I don't think the C++11 standard added anything to that effect.

You should use the full definition of the container as a template template parameter for the substitution to match; with the most explicit one as:

template <typename T, typename A, template <typename, typename> class Dest>
operator Dest<T, A>() const 
{ 
    return Dest<T, A>(m_source->begin(), m_source->end()); 
}

All the three cases compile, and the substitution matches with

[T = double, A = allocator<double>, Dest = vector],

with an old gcc-4.1.2, and with the shiny new clang-3.4 - with and without the -std=c++11 flag.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM