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模板参数将是不明确的.但是,编译器不需要演绎什么T是std::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>?
是的,它在你的例子中不起作用,因为每个模板都有两个重载,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)