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

Using std::get as parameter for std::transform

我可能在这里遗漏了一些明显的东西 - 为什么我不能以这种方式使用 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> );

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

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

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() ) 会自动为我们做正确的 const-ness。)

转换为函数的指针有点难以正确处理,必须完全正确处理所有类型。

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

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