简体   繁体   English

C ++隐式转换运算符优先级

[英]C++ Implicit Conversion Operators Precedence

EDIT: Following Mike Seymour's comment, I replaced operator std::string () const; 编辑:在迈克·西摩的评论后,我替换了operator std::string () const; with operator char * () const; 使用operator char * () const; and changed the implementation accordingly. 并相应地更改了实现。 This allows implicit casting, but, for some reason, the unsigned long int operator has precedence over the char * operator, which just does not feel right... Also, I don't want to expose nasty C stuff like char * outside the class, when I have std::string. 这允许隐式强制转换,但是由于某种原因,unsigned long int运算符的优先级高于char *运算符,这感觉不对。。而且,我不想在类,当我有std :: string时。 I have a hunch that my CustomizedInt class needs to inherit from some stuff in order to support the feature that I desire. 我有一个预感,我的CustomizedInt类需要从某些东西继承来支持我想要的功能。 Could anybody please elaborate Mike's comment regarding std::basic_string ? 有人可以详细说明Mike关于std::basic_string的评论吗? I'm not sure I understood it properly. 我不确定我是否理解正确。


I have this piece of code: 我有这段代码:

#include <string>
#include <sstream>
#include <iostream>

class CustomizedInt
{
private:
    int data;
public:
    CustomizedInt() : data(123)
    {
    }
    operator unsigned long int () const;
    operator std::string () const;
};

CustomizedInt::operator unsigned long int () const
{
    std::cout << "Called operator unsigned long int; ";
    unsigned long int output;
    output = (unsigned long int)data;
    return output;
}

CustomizedInt::operator std::string () const
{
    std::cout << "Called operator std::string; ";
    std::stringstream ss;
    ss << this->data;
    return ss.str();
}

int main()
{
    CustomizedInt x;
    std::cout << x << std::endl;
    return 0;
}

Which prints "Called operator unsigned long int; 123". 其中显示“ Called operator unsigned long int; 123”。 My questions are these: 我的问题是:

  1. After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? 删除运算符unsigned long int后,为什么需要将x强制转换为std :: string? Why does it not call the implicit cast operator (std::string) directly? 为什么不直接调用隐式强制转换运算符(std :: string)?
  2. Is there any documentation that explains which implicit casts are allowed and which is their order of precedence? 是否有任何文档说明允许哪些隐式强制转换及其优先顺序? It seems that if I add an operator unsigned int to this class together with the operator unsigned long int, I receive a compiler error about ambiguity for the << operator... 看来,如果我将运算符unsigned int与运算符unsigned long int一起添加到此类中,则会收到有关<<操作符不明确的编译器错误。
  3. Also, I know that defining such an operator may be poor practice, but I am not sure I fully understand the associated caveats. 另外,我知道定义这样的运算符可能是一种不好的做法,但是我不确定我是否完全理解相关的警告。 Could somebody please outline them? 有人可以概述一下吗? Would it be better practice to just define public methods ToUnsignedLongInt and ToString? 仅定义公共方法ToUnsignedLongInt和ToString是否是更好的做法?

After I remove the operator unsigned long int, why do I need to cast x to std::string explicitly? 删除运算符unsigned long int后,为什么需要将x强制转换为std :: string? Why does it not call the implicit cast operator (std::string) directly? 为什么不直接调用隐式强制转换运算符(std :: string)?

The version of << for strings is a template, parametrised by the parameters of the std::basic_string template ( std::string itself being a specialisation of that template). 字符串的<<版本是一个模板,由std::basic_string模板的参数设置参数( std::string本身是该模板的一种特殊形式)。 It can only be chosen by argument-dependent lookup, and that only works if the argument is actually a specialisation of std::basic_string , not something convertible to that. 它只能通过依赖于参数的查找来选择,并且仅在参数实际上是std::basic_string而不是可转换的东西时才起作用。

Is there any documentation that explains which implicit casts are allowed and which is their order of precedence? 是否有任何文档说明允许哪些隐式强制转换及其优先顺序?

The rules are quite complex, and you'd need to read the C++ standard for the full story. 规则非常复杂,您需要阅读C ++标准以获取全文。 Simple rules of thumb are that implicit conversions can't contain more than one user-defined conversion and (as you've found out) the result of an implicit conversion can't be used to choose a template specialisation by argument-dependent lookup. 简单的经验法则是,隐式转换不能包含多个用户定义的转换,并且(如您所知),隐式转换的结果不能用于通过依赖于参数的查找来选择模板特化。

I am not sure I fully understand the associated caveats. 我不确定我是否完全理解相关的警告。 Could somebody please outline them? 有人可以概述一下吗?

I don't fully understand them either; 我也不完全理解它们。 the interactions between implicit conversions, name lookup and template specialisation (and probably other factors that I can't think of right now) are rather complex, and most people don't have the inclination to learn them all. 隐式转换,名称查找和模板专业化之间的相互作用(可能还有我现在无法想到的其他因素)非常复杂,并且大多数人都不愿意全部学习它们。 There are quite a few instances where implicit conversion won't happen, and others where it might happen when you don't expect it; 在很多情况下不会发生隐式转换,而在其他情况下可能会在您不期望的情况下发生。 personally, I find it easier just to avoid implicit conversions most of the time. 就个人而言,我发现在大多数情况下避免隐式转换会更容易。

Would it be better practice to just define public methods ToUnsignedLongInt and ToString? 仅定义公共方法ToUnsignedLongInt和ToString是否是更好的做法?

That's probably a good idea, to avoid unwanted conversions. 避免不必要的转换可能是个好主意。 You can fix your problem by leaving them and use them explicitly when necessary: 您可以通过留下问题来解决问题,并在必要时明确使用它们:

std::cout << std::string(x) << std::endl;

In C++11, you can declare them explicit , so that they can only be used in this manner. 在C ++ 11中,可以将它们声明为explicit ,因此只能以这种方式使用它们。 In my opinion, that would be the best option if you can; 我认为,这将是最好的选择。 otherwise, I would use explicit conversion functions as you suggest. 否则,我将按照您的建议使用显式转换函数。

By the way, the return type of main() must be int , not void . 顺便说一句, main()的返回类型必须是int ,而不是void

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM