C++,将非指针类型赋值给模板的成员指针 class

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

在寻找二叉树实现的示例时,我注意到提供的代码中有些奇怪的地方 here。在 Node 结构的构造函数中,一个非指针类型变量被分配给一个指针类型。

它编译得很好(我使用的是 GCC 5.3.0)。让我真正困惑的是编译依赖于其他构造函数的参数,val.

它在 class 方法中没有效果,仅在构造函数中有效:

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;
    }
};

我得到的编译错误是:

invalid constructor; you probably meant ‘Test (const Test&)’

为什么会这样?标准中哪里描述了这种行为?

您的最后一个构造函数是 copy constructor。禁止有一个按值传递其参数的复制构造函数,否则你最终会无限递归。

您遇到的错误类似于

struct Foo
{
    Foo(Foo);
};

Live on Coliru

更准确地说,根据标准:

12.8/2 复制和移动 class 个对象 [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.

其他的 constructors/member 函数看起来没问题,因为它们没有被实例化,而且代码在语法上是正确的(理论上,Test<T> 可能有一个到 T* 的转换运算符用于某些特殊化,并且编译器无法在实例化之前对其进行检查)。然而,复制构造函数必须具有明确的形式,这是由编译器强制执行的。

你所有的例子都是无效的。当您尝试 实例化 任何方法时,您将遇到编译器错误:

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; ^