简体   繁体   中英

C++, assignment of non-pointer type to a member pointer of template class

While looking for a example of binary tree implementation, I've noticed something strange in the code provided here . In Node structure's constructor a non-pointer type variable is assigned to a pointer type.

It compiles just fine (I'm using GCC 5.3.0). And what made me really confused is that compilation depends on other constructor's parameter, val .

It have no effect in class methods, only in constructors:

template <typename T>
class Test {
    Test* testPtr;

    void testMethod(T t, Test<T> notAPointer) { // OK
        this->testPtr = notAPointer;
    }

    void testMethod(Test<T> notAPointer) {      // OK
        this->testPtr = notAPointer;
    }

    Test(T t, Test<T> notAPointer) {            // OK
        this->testPtr = notAPointer;
    }

    Test(Test<T> notAPointer) {                 // compilation error
        this->testPtr = notAPointer;
    }
};

The compilation error I'm getting is:

invalid constructor; you probably meant 'Test (const Test&)'

Why is that happening? Where in the standard is this behaviour described?

Your last constructor is a copy constructor . It's forbidden to have a copy constructor that passes its parameter by value, as otherwise you'd end up with infinite recursion.

The error you're getting is similar to

struct Foo
{
    Foo(Foo);
};

Live on Coliru

More precisely, according to the standard:

12.8/2 Copying and moving class objects [class.copy]

A non-template constructor for class X is a copy constructor if its first parameter is of type X& , const X& , volatile X& or const volatile X& , and either there are no other parameters or else all other parameters have default arguments (8.3.6). [ Example: X::X(const X&) and X::X(X&,int=1) are copy constructors.

The others constructors/member functions seem ok because they are not instantiated, and the code is syntactically correct (in theory, Test<T> may have a conversion operator to T* for some specialization, and the compiler cannot check that before instantiation). However the copy constructor has to have a definite form, which is being enforced by the compiler.

All of your examples are invalid. You will get a compiler error when you try to instantiate any method:

template <typename T>
struct Test {
    Test* testPtr;

    void testMethod(Test<T> notAPointer) {
        this->testPtr = notAPointer;
    }
};

int main() {
    Test<int> t1, t2;
    t1.testMethod(t2); // This line will cause the error.

    return 0;
}

prog.cpp: In instantiation of 'void Test::testMethod(Test) [with T = int]': prog.cpp:16:18: required from here prog.cpp:9:23: error: cannot convert 'Test' to 'Test*' in assignment this->testPtr = notAPointer; ^

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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