Implicit constructor argument conversion in C++11

前端 未结 3 384
礼貌的吻别
礼貌的吻别 2021-01-21 07:57

Lets concider following code:

class A{
public:
  A(int x){}
};

class B{
public:
  B(A a){};
};


int main() {
  B b = 5;
  return 0;
}

And whi

相关标签:
3条回答
  • 2021-01-21 08:11

    You can use a converting constructor that is constrained on conversions to A.

    class B {
    public:
        // It doesn't hurt to keep that one
        B(A a){};
    
        template<
            typename T
            , EnableIf<std::is_convertible<T, A>>...
        >
        B(T&& value)
        {
            // How to use the value
            A a = std::forward<T>(value);
        }
    };
    
    // Now B b = foo; is valid iff A a = foo; is, except for a few exceptions
    

    Make sure you understand the purpose of the EnableIf constraint. If you do not use it, you will face gnarly compilation errors, or worse: no errors at all. You should also carefully consider if making B convertible from potentially lots of types is at all worth it. Implicit conversions tend to make a program harder to understand, and that can quickly outweigh the apparent benefits they give.

    0 讨论(0)
  • 2021-01-21 08:24

    Just to be clear:

    B b = 5;
    

    is "copy initialisation" not assignment. (See http://www.gotw.ca/gotw/036.htm).

    In this case, you are asking the compiler to perform two implicit user-defined conversions first, i.e. int -> A, A -> B before a temporary B object is passed to the copy constructor for B b. The compiler is allowed to elide the temporary object but semantically you are still asking the language to make two jumps across types.

    All implicit behaviour in programming languages is inherently scary. For the sake of a little syntactic sugar, we are asking c++ to "do some magic to make it just work". Unexpected type conversions can wreck havoc in large complex programmes. Otherwise, every time you wrote a new function or a new class, you would have to worry about all the other types and functions it could affect, with the side -effects rippling across your code. Would you really want implicit conversions from int -> apple -> horse -> horse_power -> aeroplane?

    For that reason, c++ only allows a single implicit user-defined conversion:

    12.3 Conversions [class.conv]

    1 Type conversions of class objects can be specified by constructors and by conversion functions. These conversions are called user-defined conversions and are used for implicit type conversions (clause 4), for initialization (8.5), and for explicit type conversions (5.4, 5.2.9).

    4 At most one user-defined conversion (constructor or conversion function) is implicitly applied to a single value.

    You are better off either with an explicit cast or "direct initialisation" both of which make it clear to the compiler and collaborators exactly what you are trying to do. Either the traditional or the new uniform initialisation syntax works:

    B b(5);
    B b{5};
    B b = {5};
    
    0 讨论(0)
  • 2021-01-21 08:35

    Use direct initialisation instead:

    B b(5);
    
    0 讨论(0)
提交回复
热议问题