c++ - 强制转换为 void 以避免使用重载的用户定义逗号运算符
问题描述
我正在学习 C++ 中的模板,并遇到了一个void
使用强制转换的示例:
template<typename T>
auto func (T const& t) -> decltype( (void)(t.size()), T::size_type() )
{
return t.size();
}
在解释中写道:
将表达式强制转换为 void 是为了避免用户定义的逗号运算符为表达式类型重载的可能性。
我的问题是/是:
如何使用强制转换为 void 来“避免用户定义的逗号运算符为表达式类型重载的可能性”?我的意思是,谁能举
void
个例子,如果我们不使用,那么这段代码会出错?例如,假设我们有一个名为的类SomeClass
,它重载了逗号运算符。现在,如果我们不使用,这会成为问题void
吗?可以
static_cast
在这种情况下使用而不是 C 样式转换吗?例如,类似static_cast<void>(t.size())
. 我正在阅读使用 C++17 特性的示例,所以我想知道为什么作者在这种情况下使用了 C 样式转换。
我已经阅读了强制转换为 `void` 的真正作用是什么?,从中我得到的印象是,如果我们使用(void)x
then 这意味着禁止编译器警告,也意味着“忽略 x 的值”。但是后来我无法理解表达式x
和之间的区别(void)x
。
解决方案
考虑这种病理类型:
struct foo {
struct size_type {
bool operator,(size_type) { return false;}
};
size_type size() { return {};}
};
它确实有一个size_type
并且确实有一个size()
方法。但是,如果没有转换为void
,则模板不会推断出正确的返回类型,因为decltype( (t.size()), typename T::size_type() )
is bool
:
#include <type_traits>
template<typename T>
auto func (T const& t) -> decltype( (t.size()), typename T::size_type() )
{
return t.size();
}
struct foo {
struct size_type {
bool operator,(size_type) { return false;}
};
size_type size() const { return {};}
};
int main()
{
func(foo{});
}
结果错误:
<source>:6:8: error: no viable conversion from returned value of type 'foo::size_type' to function return type 'decltype((t.size()) , typename foo::size_type())' (aka 'bool')
return t.size();
^~~~~~~~
<source>:20:4: note: in instantiation of function template specialization 'func<foo>' requested here
func(foo{});
^
1 error generated.
ASM generation compiler returned: 1
<source>:6:8: error: no viable conversion from returned value of type 'foo::size_type' to function return type 'decltype((t.size()) , typename foo::size_type())' (aka 'bool')
return t.size();
^~~~~~~~
<source>:20:4: note: in instantiation of function template specialization 'func<foo>' requested here
func(foo{});
^
static_cast
可以使用一个。但是,由于实际上没有进行任何转换(这是一个未评估的上下文),因此 c 样式转换不会造成太大的伤害。请注意如何绕过void
对用户定义operator,
的强制转换并推断出正确的返回类型:https ://godbolt.org/z/jozx1YGWr 。这是因为void, whatever
使用了operator,
结果与whatever
. 您不能void, whatever
使用用户定义的operator,
; 没有有效的语法。
我想代码只是为了说明这一效果,因为即使强制转换为void
one 也可以弥补其他失败的示例(例如,模板没有明确地测试t.size()
实际返回T::size_type
)。
另请参阅此处的“很少重载运算符”部分:
逗号运算符,
operator,
. 与内置版本不同,重载不会将其左操作数排序在右操作数之前。(直到 C++17)因为此运算符可能会被重载,所以泛型库使用诸如a,void(),b
代替a,b
序列执行用户定义类型的表达式的表达式。boost 库在 boost.assign、boost.spirit 和其他库中使用运算符。数据库访问库 SOCI 也重载operator,
。
推荐阅读
- raku - MacOS 上的 Raku Comma IDE 无法启动
- angular - 为 Angular 组件测试生成 @Component 定义运行时
- typescript - 类型检查类型的索引值
- pandas - 如何将 pandas 对象传递给 numpy 函数?
- flutter - 如何从 Flutter 中的另一个类访问地图?
- r - 循环数据时计算错误
- python - 如何在没有地理信息的情况下通过插值重新网格化数据?
- python - Django:如何检查用户是否在过去 7 天内注册?
- c++ - Rust 智能指针 std::rc::Rc 和 std::sync::Arc 是否分别类似于 C++ 智能指针 std::shared_ptr 和 std::atomic_shared_ptr?
- python - 有没有办法强制熊猫数据框查询使用“python”作为默认引擎?