使用std :: get作为std :: transform的参数

时间:2015-02-03 22:04:16

标签: c++ std

我可能会遗漏一些明显的东西 - 为什么我不能以这种方式使用std :: get?

#include <map>
#include <iterator>
#include <set>
#include <algorithm>
#include <utility>

int main() {
    std::map<int, double> some_map;
    std::set<int> set_of_ints;
    std::transform( 
        some_map.begin(), 
        some_map.end(), 
        std::inserter( set_of_ints, set_of_ints.begin() ), 
        std::get<0> );
    return 0;
}

我试过的编译器是VS2010以及Ideone.com用于C ++ 14的一些编辑器(一些最近的GCC?)。这是后者的输出:

prog.cpp: In function 'int main()':
prog.cpp:17:28: error: no matching function for call to 'transform(std::map<int, double>::iterator, std::map<int, double>::iterator, std::insert_iterator<std::set<int> >, <unresolved overloaded function type>)'
   std::get<0, int, double> );
                            ^
prog.cpp:17:28: note: candidates are:
In file included from /usr/include/c++/4.9/algorithm:62:0,
                 from prog.cpp:5:
/usr/include/c++/4.9/bits/stl_algo.h:4152:5: note: template<class _IIter, class _OIter, class _UnaryOperation> _OIter std::transform(_IIter, _IIter, _OIter, _UnaryOperation)
     transform(_InputIterator __first, _InputIterator __last,
     ^
/usr/include/c++/4.9/bits/stl_algo.h:4152:5: note:   template argument deduction/substitution failed:
prog.cpp:17:28: note:   couldn't deduce template parameter '_UnaryOperation'
   std::get<0, int, double> );
                            ^
In file included from /usr/include/c++/4.9/algorithm:62:0,
                 from prog.cpp:5:
/usr/include/c++/4.9/bits/stl_algo.h:4189:5: note: template<class _IIter1, class _IIter2, class _OIter, class _BinaryOperation> _OIter std::transform(_IIter1, _IIter1, _IIter2, _OIter, _BinaryOperation)
     transform(_InputIterator1 __first1, _InputIterator1 __last1,
     ^
/usr/include/c++/4.9/bits/stl_algo.h:4189:5: note:   template argument deduction/substitution failed:
prog.cpp:17:28: note:   candidate expects 5 arguments, 4 provided
   std::get<0, int, double> );

2 个答案:

答案 0 :(得分:2)

编译器无法决定使用以下两个重载中的哪一个。

int std::get<0, int, double>(const std::tuple<int, double>&)
int std::get<0, int, double>(const std::pair<int, double>&)

我没有看到任何方法让编译器选择其中一个。

您可能必须使用lambda或定义T1 pair_first<T1, T2>(const std::pair<T1, T2>&)函数,然后再传递pair_first

答案 1 :(得分:2)

std::get<0>替换为以下其中一项:

[](       std:: pair<const int, double>  &x){return std:: get<0>(x);}
// or
[](       decltype( *some_map.begin() )  &x){return std:: get<0>(x);}
// or
[](       decltype(some_map)::value_type &x){return std:: get<0>(x);}
// or cast to a function pointer
(const int & (*)(std::pair<const int,double> &)) std::get<0,const int,double>

在clang 3.5.0上测试过。这会强制它std::get使用pair,而不是tuple

另外,也许你应该在每个人面前const,如下:

[]( const std:: pair<const int, double>  &x){return std:: get<0>(x);}
// or
[]( const decltype( *some_map.begin() )  &x){return std:: get<0>(x);}
// or
[]( const decltype(some_map)::value_type &x){return std:: get<0>(x);}

(实际上,我认为中间的decltype( *some_map.begin() )会自动为我们做正确的约束。)

强制转换功能指针有点尴尬,必须让所有类型完全正确。

最后,受@ chris的启发,这是一个C ++ 14解决方案(如果你想将其复制并粘贴到其他代码中,还有一些完美的转发):

[](auto&& x){return std:: get<0>(std::forward<decltype(x)>(x));}