gpt4 book ai didi

c++ - 为什么 `std::reference_wrapper` 秒内不能推导出模板实例?

转载 作者:IT老高 更新时间:2023-10-28 22:21:24 26 4
gpt4 key购买 nike

假设我有一些 T 类型的对象,我想把它放到一个引用包装器中:

int a = 5, b = 7;

std::reference_wrapper<int> p(a), q(b); // or "auto p = std::ref(a)"

现在我可以轻松地说if (p < q) ,因为引用包装器具有到其包装类型的转换。一切都很好,我可以像处理原始对象一样处理引用包装器的集合。

(正如 question linked below 所示,这可能是生成现有集合的替代 View 的有用方法,可以随意重新排列而不产生完整拷贝的成本,以及维护更新与原始集合的完整性。)


但是,对于某些类,这不起作用:

std::string s1 = "hello", s2 = "world";

std::reference_wrapper<std::string> t1(s1), t2(s2);

return t1 < t2; // ERROR

我的解决方法是定义一个谓词,如this answer *;但我的问题是:

为什么以及何时可以将运算符应用于引用包装器并透明地使用包装类型的运算符?为什么 std::string 会失败?这与 std::string 有什么关系?是模板实例吗?

*) 更新:根据答案,似乎使用 std::less<T>()是一个通用的解决方案。

最佳答案

编辑: 将我的猜测移至底部,这是为什么这不起作用的规范文本。 TL;DR 版本:

No conversions allowed if the function parameter contains a deduced template parameter.


§14.8.3 [temp.over] p1

[...] When a call to that name is written (explicitly, or implicitly using the operator notation), template argument deduction (14.8.2) and checking of any explicit template arguments (14.3) are performed for each function template to find the template argument values (if any) that can be used with that function template to instantiate a function template specialization that can be invoked with the call arguments.

§14.8.2.1 [temp.deduct.call] p4

[...] [ Note: as specified in 14.8.1, implicit conversions will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter contains no template-parameters that participate in template argument deduction. [...] —end note ]

§14.8.1 [temp.arg.explicit] p6

Implicit conversions (Clause 4) will be performed on a function argument to convert it to the type of the corresponding function parameter if the parameter type contains no template-parameters that participate in template argument deduction. [ Note: Template parameters do not participate in template argument deduction if they are explicitly specified. [...] —end note ]

自从 std::basic_string取决于推导出的模板参数( CharTTraits ),不允许转换。


这是一个先有鸡还是先有蛋的问题。要推导出模板参数,它需要 std::basic_string 的实际实例。 .要转换为包装类型,需要一个转换目标。该目标必须是实际类型,而类模板不是。编译器必须测试 std::basic_string 的所有可能实例化。反对转换运算符或类似的东西,这是不可能的。

假设以下最小测试用例:

#include <functional>

template<class T>
struct foo{
int value;
};

template<class T>
bool operator<(foo<T> const& lhs, foo<T> const& rhs){
return lhs.value < rhs.value;
}

// comment this out to get a deduction failure
bool operator<(foo<int> const& lhs, foo<int> const& rhs){
return lhs.value < rhs.value;
}

int main(){
foo<int> f1 = { 1 }, f2 = { 2 };
auto ref1 = std::ref(f1), ref2 = std::ref(f2);
ref1 < ref2;
}

如果我们不为 int 上的实例化提供重载,扣减失败。如果我们提供该重载,编译器可以使用允许的用户定义转换(foo<int> const& 是转换目标)对其进行测试。由于在这种情况下转换匹配,重载解析成功,我们得到了函数调用。

关于c++ - 为什么 `std::reference_wrapper` 秒内不能推导出模板实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8513050/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com