为什么不能从std :: addressof <int>解析模板参数?

Már*_*ldi 1 c++ templates stl

Clang和GCC(MSVC除外)在std::addressof<int>作为参数传递给模板函数时无法解析模板参数.以下是此类错误的示例:

std::vector<int> v{1,2,3,4,5};
std::vector<int*> pv(iv.size());
std::transform(v.begin(), v.end(), pv.begin(), std::addressof<int>);
Run Code Online (Sandbox Code Playgroud)

铛:

<source>:8:5: error: no matching function for call to 'transform'
    std::transform(iv.begin(), iv.end(), piv.begin(), std::addressof<int>);
    ^~~~~~~~~~~~~~
/opt/compiler-explorer/clang-5.0.0/bin/../include/c++/v1/algorithm:2028:1: note: candidate template ignored: couldn't infer template argument '_UnaryOperation'
transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __op)
^
Run Code Online (Sandbox Code Playgroud)

GCC:

/opt/compiler-explorer/gcc-7.2.0/include/c++/7.2.0/bits/stl_algo.h:4295:5: note:   template argument deduction/substitution failed:
<source>:8:74: note:   could not resolve address from overloaded function 'addressof<int>'
     std::transform(iv.begin(), iv.end(), piv.begin(), std::addressof<int>);
                                                                          ^
Run Code Online (Sandbox Code Playgroud)

如果参数是a std::addressof,那么该错误将是有意义的,因为UnaryOperator模板参数将是不明确的.但是,编译器不需要演绎什么Tstd::addressof<int>,我会在这里不放过任何歧义.

这是我期望的一个有效例子(编译Clang 5和GCC 7.2):

template <typename T>
T* addrof(T& a)
{
    return __builtin_addressof(a);  
}

template <typename F, typename T>
void foo(F f, T& a)
{
    f(a);
}

int main()
{
    int a = 42;
    foo(addrof<int>, a);
}
Run Code Online (Sandbox Code Playgroud)

我的疑问是:为什么不能std::transform从中推导出模板参数std::addressof<int>

Ser*_*eyA 5

是的,它在你的例子中不起作用,因为每个模板都有两个重载,std::addressof因为C++ 17(一个获取地址,一个删除版本采用rvalue引用),并且编译器选择哪一个是不明确的.最简单的解决方案是使用lambda:

#include <vector>
#include <algorithm>

void foo() {
   std::vector<int> v{1,2,3,4,5};
   std::vector<int*> pv(v.size());
   std::transform(v.begin(), v.end(), pv.begin(), 
                  [](int& i) { return std::addressof(i);});
}
Run Code Online (Sandbox Code Playgroud)

这些重载列于此处:http://en.cppreference.com/w/cpp/memory/addressof

另一个选择是使用演员,但它只是丑陋,你应该喜欢Lambdas!然而,将提供完整性:

#include <vector>
#include <algorithm>

void foo() {
   std::vector<int> v{1,2,3,4,5};
   std::vector<int*> pv(v.size());

   std::transform(v.begin(), v.end(), pv.begin(), 
                  static_cast<int* (*)(int&) >(std::addressof<int>));
}
Run Code Online (Sandbox Code Playgroud)