Chris
Chris

Reputation: 6732

C++ - call assignment operator at creation instead of copy constructor

I want to enforce explicit conversion between structs kind of like native types:

int i1;
i1 = some_float; // this generates a warning
i1 = int(some_float): // this is OK
int i3 = some_float; // this generates a warning

I thought to use an assignment operator and copy constructor to do the same thing, but the behavior is different:

Struct s1;
s1 = other_struct; // this calls the assignment operator which generates my warning
s1 = Struct(other_struct) // this calls the copy constructor to generate a new Struct and then passes that new instance to s1's assignment operator
Struct s3 = other_struct; // this calls the COPY CONSTRUCTOR and succeeds with no warning

Are there any tricks to get that third case Struct s3 = other_struct; construct s3 with the default constructor and then call the assignment operator?

This all compiles and runs as it should. The default behavior of C++ is to call the copy constructor instead of the assignment operator when you create a new instance and call the copy constructor at once, (i.e. MyStruct s = other_struct;becomes MyStruct s(other_struct); not MyStruct s; s = other_struct;. I'm just wondering if there are any tricks to get around that.

EDIT: The "explicit" keyword is just what I needed!

class foo {
    foo(const foo& f) { ... }
    explicit foo(const bar& b) { ... }
    foo& operator =(const foo& f) { ... }
};

foo f;
bar b;
foo f2 = f; // this works
foo f3 = b; // this doesn't, thanks to the explicit keyword!
foo f4 = foo(b); // this works - you're forced to do an "explicit conversion"

Upvotes: 0

Views: 1684

Answers (4)

Alexandre C.
Alexandre C.

Reputation: 56956

Disclaimer: I'm ready to take the downvotes on this, since this doesn't answer the question. But this could be useful to the OP.

I think it is a very bad idea to think of the copy constructor as default construction + assignment. It is the other way around:

struct some_struct
{
    some_struct();  // If you want a default constructor, fine
    some_struct(some_struct const&); // Implement it in the most natural way
    some_struct(foo const&);         // Implement it in the most natural way

    void swap(some_struct&) throw(); // Implement it in the most efficient way

    // Google "copy and swap idiom" for this one
    some_struct& operator=(some_struct x) { x.swap(*this); return *this; }

    // Same idea
    some_struct& operator=(foo const& x)
    {
        some_struct tmp(x);
        tmp.swap(*this);
        return *this;
    }
};

Implementing things that way is fool proof, and is the best you can obtain in term of conversion semantics in C++, so it is the way to go here.

Upvotes: 4

Paul
Paul

Reputation: 2238

You can get around this if you overload the type cast operator for other_struct, and edit the original structure accordingly. That said, it's extremely messy and there generally isn't a good reason to do so.


#include <iostream>

using namespace std;

struct bar;

struct foo {
    explicit foo() {
        cout << "In foo default constructor." << endl;
    }

    explicit foo(bar const &) {
        cout << "In foo 'bar' contructor." << endl;
    }

    foo(foo const &) {
        cout << "In foo constructor." << endl;
    }

    foo const & operator=(bar const &) {
        cout << "In foo = operator." << endl;
        return *this;
    }
};

struct bar {
    operator foo() {
        cout << "In bar cast overload." << endl;
        foo x;
        x = *this;
        return x;
    }
};

int main() {
    bar b;
    foo f = b;
    return 0;
}

Outputs:

In bar cast overload.
In foo default constructor.
In foo = operator.
In foo constructor.
In foo constructor.

Upvotes: 3

Reinderien
Reinderien

Reputation: 15221

I don't think so. When you write

Struct s3 = other_struct;

It looks like an assignment, but really it's just declarative syntax that calls a constructor.

Upvotes: 0

Edward Strange
Edward Strange

Reputation: 40859

In short, no.

The long version...actually that's about it. That's just not how it works. Had to come up with something to fill the character requirement though.

Upvotes: 2

Related Questions