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

Why can't template argument be resolved from std::addressof<int>?

本文关键字:lt int gt 解析 不能 std 为什么 addressof 参数      更新时间:2023-10-16

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>);

铛:

<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)
^

海湾合作委员会:

/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>);
    ^

如果参数是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);
}

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

是的,它在您的示例中不起作用,因为自 C++ 17 年以来,每个模板std::addressof都有两个重载(一个获取地址和一个删除的版本,它采用右值引用),并且编译器选择哪一个是不明确的。最简单的解决方案是使用 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);});
}

下面列出了这些重载:http://en.cppreference.com/w/cpp/memory/addressof

另一种选择是使用cast,但它只是丑陋,你应该更喜欢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>));
}