Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::make_pair : cannot convert 'ch' (type 'char') to type 'char&&' [duplicate]

Tags:

c++

c++11

What's is wrong with the following code:

#include <ctime>
#include <vector>
#include <utility>
#include <algorithm>
#include <iostream>

int main()
{
    std::vector< std::pair< char, unsigned > > vec;

    for( unsigned i = 0; i < 100; ++i )
    {
        char ch = 0;
        unsigned number = 0;

        do {
            ch = i;
            number = i;

        } while( std::find( vec.begin(), vec.end(), std::make_pair< char, unsigned >( ch, number ) ) != vec.end() );

        std::cout << ch << number << '\n';

        vec.push_back( std::make_pair< char, unsigned >( ch, number ) );
    }
}

It does compile nicely with:

g++ test.cxx

but fails with:

$ g++ -std=c++11 test.cxx                                                                                                              /tmp
test.cxx: In function 'int main()':
test.cxx:21:98: error: no matching function for call to 'make_pair(char&, unsigned int&)'
test.cxx:21:98: note: candidate is:
In file included from /usr/include/c++/4.7/bits/stl_algobase.h:65:0,
                 from /usr/include/c++/4.7/vector:61,
                 from test.cxx:3:
/usr/include/c++/4.7/bits/stl_pair.h:268:5: note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
/usr/include/c++/4.7/bits/stl_pair.h:268:5: note:   template argument deduction/substitution failed:
test.cxx:21:98: note:   cannot convert 'ch' (type 'char') to type 'char&&'
test.cxx:25:69: error: no matching function for call to 'make_pair(char&, unsigned int&)'
test.cxx:25:69: note: candidate is:
In file included from /usr/include/c++/4.7/bits/stl_algobase.h:65:0,
                 from /usr/include/c++/4.7/vector:61,
                 from test.cxx:3:
/usr/include/c++/4.7/bits/stl_pair.h:268:5: note: template<class _T1, class _T2> constexpr std::pair<typename std::__decay_and_strip<_Tp>::__type, typename std::__decay_and_strip<_T2>::__type> std::make_pair(_T1&&, _T2&&)
/usr/include/c++/4.7/bits/stl_pair.h:268:5: note:   template argument deduction/substitution failed:
test.cxx:25:69: note:   cannot convert 'ch' (type 'char') to type 'char&&'
like image 640
malat Avatar asked Feb 26 '13 18:02

malat


1 Answers

SOLUTION:

Instead of explicitly specifying the template arguments to make_pair<>() this way:

std::make_pair< char, unsigned >( ch, number )

Just let them be deduced:

std::make_pair( ch, number )

EXPLANATION:

The rationale behind this guideline is found in the way std::make_pair<>() is defined, and in the way template argument deduction works for universal references. From Paragraph 20.3.3/8-9 of the C++11 Standard:

template <class T1, class T2> pair<V1, V2> make_pair(T1&& x, T2&& y);

Returns: pair<V1, V2>(std::forward<T1>(x), std::forward<T2>(y)); where V1 and V2 are determined as follows: Let Ui be decay<Ti>::type for each Ti. Then each Vi is X& if Ui equals reference_wrapper<X>, otherwise Vi is Ui. [ Example: In place of:

return pair<int, double>(5, 3.1415926); // explicit types

a C++ program may contain:

return make_pair(5, 3.1415926); // types are deduced

end example ]

Here, T1 and T2 are meant to be deduced. By explicitly specifying the template arguments yourself, you're getting on the way of make_pair<>()'s type deduction machinery to produce the correct return type, forcing the instantiation of a function which accepts an rvalue reference to char and and rvalue reference to unsigned:

... make_pair(char&&, unsigned&&)

However, you are not providing rvalues in input, because ch and number are lvalues. This is what the compiler is complaining about.


ALTERNATIVE:

Also notice, that you can implicitly construct an std::pair object, which saves your from calling make_pair<>() at all:

vec.push_back( { ch, number } );
like image 156
Andy Prowl Avatar answered Oct 29 '22 11:10

Andy Prowl