为什么我不能将 class 之外的 C++ 转换运算符重载为 non-member 函数?
Why can't I overload C++ conversion operators outside a class, as a non-member function?
这个问题以前有人问过,但我觉得提问者在他从未真正得到真正答案的情况下匆忙说出正确答案。也许没有理由,这需要稍后放入标准中,你告诉我。
What is the rationale to not allow overloading of C++ conversions operator with non-member functions
我正在寻找不允许将其作为当前标准设计的一部分的具体原因。基本上,当您重载强制转换运算符以定义两种类型之间的隐式转换时,此重载定义必须是您正在转换的 class 的成员,而不是 class 之外的内容。一个明显的问题是,如果你有一些类型,你真的因为某种原因不能修改,但你想在它们之间隐式转换,为了语法简单(尽管隐式转换有弊端),或者因为你有一堆其他依赖于隐式转换的代码、标准或自定义……如果你不能向 classes 添加适当的隐式转换,你就不能这样做,所以你需要使用像常规函数这样的变通方法来进行转换将环绕隐式转换的便利性。
此外,在 class 之外添加这些转换是否真的可能会产生计算开销?在我看来,编译器很容易在找出可用的函数时,将外部隐式转换函数与它们转换的 class 相关联,以便代码像原来一样执行就效率而言,class 的一部分。唯一的缺点是它必须做一些额外的工作来建立初始关联,这应该几乎没有。
我不会把 "because the standard says so" 或 "because implicit conversions are bad" 作为答案。有人在编写实际标准时肯定有理由。
(我不是专家,我还在学习这门语言。)
编辑,回复:
好吧,我想情况可能是这样的,是的,你更改了 header 文件,但你不做的是覆盖现有的文件,因为那样会很糟糕。您将基于旧文件创建一个新的 header 文件以适应更改。假设旧代码已经编译在 object 文件中,更改 header 只是告诉编译器您在其他地方添加了其他代码。它不会改变旧代码的作用,因为它已经编译并且不依赖于旧代码(即一些供应商交给您 object 代码和 header)。如果我可以修改并重新编译我将使用转换的代码,那么你不能让我在外部编写转换函数,我不会这样做,这太混乱了。您不必随机搜索每个 header 来寻找正确的定义;如果我自己编写代码,我会制作一个带有高度可见部分的自定义 header,其中我添加到 vendor-supplied header 的内容是,并且说 header 是它是哪一个相对明显,因为它会与相关类型相关联,而其他 headers 将以其原始名称命名,因此您会知道它们没有被更改。并且您将有一个仅包含转换定义的相应文件,因此我的修改将是 self-contained,与原始 object 代码分开,并且相对容易找到。当然,这与在代码中找出应用哪个转换函数的实际斗争不同。我认为您可以找到各种情况,在这些情况下,它很容易确定并且很自然地可以使用,并且可以出于您自己的目的添加到像这样的现有库中。如果我使用的是我无法真正修改的商业代码,并且我看到可以通过使用转换函数将它与我自己的一些东西集成来改进我正在做的事情的情况,我可以看到自己想要做的这个。当然,对于仅阅读 a = b 的第三人来说,这些事情并不明显,他们不会仅仅从那里知道我的转换发生了什么,但如果你知道并且它读起来很好,那么它就可以工作。
我很欣赏关于标准决策如何运作的洞察力,这绝对是一种你可以忽略的边缘事物。
除了 non-explicit 转换运算符,例如operator bool()
在 class 中,您还可以让 non-explicit 构造函数采用单个参数,在 class 中,您正在将 转换为 ,作为引入 user-defined 转换的一种方式。 (问题中未提及)
至于为什么不能在不修改定义的情况下在两种类型 A
和 B
之间引入 user-defined 转换...好吧,这会造成混乱。
如果你能做到这一点,那么你就可以在 header 文件中做到这一点,并且由于引入新的 user-defined 转换可以改变代码的含义,这意味着 "old" 仅使用 A
和 B
的代码可能会完全改变它正在做的事情,具体取决于您的 header 是否包含在它之前,或者类似的东西。
即使有转换必须由两种类型之一声明的限制,也很难准确地弄清楚当事情出错时发生了什么 user-defined 转换序列。如果您真的必须完全搜索每个不相关的 header 文件以找到这些转换函数定义,这会大大恶化维护问题,并且允许这样做似乎没有任何好处。我的意思是,您能否举一个 non-contrived 示例,说明此语言功能可以帮助您实现更简单或更易于阅读的内容?
总的来说,我认为程序员喜欢这样的想法,即要弄清楚一行 a = b;
的作用,他们只需要阅读 a
类型的定义和 b
然后从那里开始......如果您开始允许这些 "gotcha" 更难了解的转换,它可能会变得丑陋和痛苦。
我猜你可以对 operator <<
用于流式传输说同样的话......但是 user-defined 转换更严重,因为它可能会影响 any 行代码,该类型的 object 作为参数传递。
此外,我认为您不一定期望找到 well-thought 原因,并非标准允许编译器实现的所有可行的东西。委员会倾向于保守并寻求共识,因此 "no one really cared about feature X enough to fight for it" 可能是一个很好的解释,你会发现为什么功能 X 不可用。
对该问题的回答表明了功能不可用的常见原因:
- Legacy: the feature was left out in the first place and now we've built a lot without it that it's almost forgotten (see partial function template specialization).
这个问题以前有人问过,但我觉得提问者在他从未真正得到真正答案的情况下匆忙说出正确答案。也许没有理由,这需要稍后放入标准中,你告诉我。 What is the rationale to not allow overloading of C++ conversions operator with non-member functions
我正在寻找不允许将其作为当前标准设计的一部分的具体原因。基本上,当您重载强制转换运算符以定义两种类型之间的隐式转换时,此重载定义必须是您正在转换的 class 的成员,而不是 class 之外的内容。一个明显的问题是,如果你有一些类型,你真的因为某种原因不能修改,但你想在它们之间隐式转换,为了语法简单(尽管隐式转换有弊端),或者因为你有一堆其他依赖于隐式转换的代码、标准或自定义……如果你不能向 classes 添加适当的隐式转换,你就不能这样做,所以你需要使用像常规函数这样的变通方法来进行转换将环绕隐式转换的便利性。
此外,在 class 之外添加这些转换是否真的可能会产生计算开销?在我看来,编译器很容易在找出可用的函数时,将外部隐式转换函数与它们转换的 class 相关联,以便代码像原来一样执行就效率而言,class 的一部分。唯一的缺点是它必须做一些额外的工作来建立初始关联,这应该几乎没有。
我不会把 "because the standard says so" 或 "because implicit conversions are bad" 作为答案。有人在编写实际标准时肯定有理由。
(我不是专家,我还在学习这门语言。)
编辑,回复: 好吧,我想情况可能是这样的,是的,你更改了 header 文件,但你不做的是覆盖现有的文件,因为那样会很糟糕。您将基于旧文件创建一个新的 header 文件以适应更改。假设旧代码已经编译在 object 文件中,更改 header 只是告诉编译器您在其他地方添加了其他代码。它不会改变旧代码的作用,因为它已经编译并且不依赖于旧代码(即一些供应商交给您 object 代码和 header)。如果我可以修改并重新编译我将使用转换的代码,那么你不能让我在外部编写转换函数,我不会这样做,这太混乱了。您不必随机搜索每个 header 来寻找正确的定义;如果我自己编写代码,我会制作一个带有高度可见部分的自定义 header,其中我添加到 vendor-supplied header 的内容是,并且说 header 是它是哪一个相对明显,因为它会与相关类型相关联,而其他 headers 将以其原始名称命名,因此您会知道它们没有被更改。并且您将有一个仅包含转换定义的相应文件,因此我的修改将是 self-contained,与原始 object 代码分开,并且相对容易找到。当然,这与在代码中找出应用哪个转换函数的实际斗争不同。我认为您可以找到各种情况,在这些情况下,它很容易确定并且很自然地可以使用,并且可以出于您自己的目的添加到像这样的现有库中。如果我使用的是我无法真正修改的商业代码,并且我看到可以通过使用转换函数将它与我自己的一些东西集成来改进我正在做的事情的情况,我可以看到自己想要做的这个。当然,对于仅阅读 a = b 的第三人来说,这些事情并不明显,他们不会仅仅从那里知道我的转换发生了什么,但如果你知道并且它读起来很好,那么它就可以工作。
我很欣赏关于标准决策如何运作的洞察力,这绝对是一种你可以忽略的边缘事物。
除了 non-explicit 转换运算符,例如
operator bool()
在 class 中,您还可以让 non-explicit 构造函数采用单个参数,在 class 中,您正在将 转换为 ,作为引入 user-defined 转换的一种方式。 (问题中未提及)至于为什么不能在不修改定义的情况下在两种类型
A
和B
之间引入 user-defined 转换...好吧,这会造成混乱。如果你能做到这一点,那么你就可以在 header 文件中做到这一点,并且由于引入新的 user-defined 转换可以改变代码的含义,这意味着 "old" 仅使用
A
和B
的代码可能会完全改变它正在做的事情,具体取决于您的 header 是否包含在它之前,或者类似的东西。即使有转换必须由两种类型之一声明的限制,也很难准确地弄清楚当事情出错时发生了什么 user-defined 转换序列。如果您真的必须完全搜索每个不相关的 header 文件以找到这些转换函数定义,这会大大恶化维护问题,并且允许这样做似乎没有任何好处。我的意思是,您能否举一个 non-contrived 示例,说明此语言功能可以帮助您实现更简单或更易于阅读的内容?
总的来说,我认为程序员喜欢这样的想法,即要弄清楚一行
a = b;
的作用,他们只需要阅读a
类型的定义和b
然后从那里开始......如果您开始允许这些 "gotcha" 更难了解的转换,它可能会变得丑陋和痛苦。我猜你可以对
operator <<
用于流式传输说同样的话......但是 user-defined 转换更严重,因为它可能会影响 any 行代码,该类型的 object 作为参数传递。
此外,我认为您不一定期望找到 well-thought 原因,并非标准允许编译器实现的所有可行的东西。委员会倾向于保守并寻求共识,因此 "no one really cared about feature X enough to fight for it" 可能是一个很好的解释,你会发现为什么功能 X 不可用。
对该问题的回答表明了功能不可用的常见原因:
- Legacy: the feature was left out in the first place and now we've built a lot without it that it's almost forgotten (see partial function template specialization).