强制转换为 void 以避免使用重载的用户定义逗号运算符

use*_*570 5 c++ casting void c++11 c++17

void我正在学习 C++ 中的模板,并遇到了一个使用强制转换的示例:

template<typename T>
auto func (T const& t) -> decltype( (void)(t.size()), T::size_type() )
{
return t.size();

}
Run Code Online (Sandbox Code Playgroud)

解释中写道:

将表达式强制转换为 void 是为了避免用户定义的逗号运算符针对表达式类型重载的可能性。

我的问题是:

  1. 如何使用强制转换为 void 来“避免用户定义的逗号运算符重载表达式类型的可能性”?我的意思是,任何人都可以举出任何例子,如果我们不使用void此代码会给出错误吗?例如,假设我们有一个名为 的类SomeClass,它重载了逗号运算符。现在,如果我们不使用,这会成为问题吗void

  2. static_cast在这种情况下可以使用 C 风格的强制转换吗?例如,类似的东西static_cast<void>(t.size())。我正在阅读使用 C++17 功能的示例,因此我想知道为什么作者在这种情况下使用了 C 风格转换。

我读过强制转换为“void”到底有什么作用?,从中我得到的印象是,如果我们使用(void)xthen 这意味着抑制编译器警告,并且还意味着“忽略 x 的值”。但后来我无法理解表达式x和之间的区别(void)x

for*_*818 7

考虑这种病理类型:

struct foo {
    struct size_type {
        bool operator,(size_type) { return false;}
    };
    size_type size() { return {};}  
};
Run Code Online (Sandbox Code Playgroud)

它确实有一个size_type并且它确实有一个size()方法。但是,如果没有强制转换为void,模板将无法推导出正确的返回类型,decltype( (t.size()), typename T::size_type() )因为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{});
}
Run Code Online (Sandbox Code Playgroud)

结果错误

<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{});
   ^
Run Code Online (Sandbox Code Playgroud)

static_cast可以用A. 然而,由于实际上没有任何东西被转换(它是一个未评估的上下文),所以 c 风格的转换不会造成太大的伤害。void请注意如何通过使用对用户定义的强制转换operator,来绕过并推导出正确的返回类型: https: //godbolt.org/z/jozx1YGWr。这是因为使用了其结果与 类型相同的void, whatever内置函数。您不能使用用户定义的覆盖;没有有效的语法。operator,whatevervoid, whateveroperator,

我认为代码只是为了说明这一效果,因为即使转换为void1 也可以弥补其他失败的示例(例如,模板没有显式测试t.size()实际返回T::size_type)。


另请参阅此处有关“很少重载的运算符”的部分:

逗号运算符,operator,. 与内置版本不同,重载不会将左操作数排在右操作数之前。(C++17 之前)由于此运算符可能会重载,因此泛型库使用诸如a,void(),b代替之类的表达式a,b来顺序执行用户定义类型的表达式。boost 库用于operator,boost.assign、boost.spirit 和其他库。数据库访问库 SOCI 也超载operator,

  • @JasonLiam 不可能声明一个具有“void”类型参数的用户定义“运算符”。因此,当参数之一的类型为“void”时,唯一可以使用的“运算符”是内置运算符。 (2认同)