2016-02-13 2 views
3

При поиске примера реализации двоичного дерева я заметил что-то странное в приведенном коде here. В Узел Конструктор структуры переменной типа non-pointer присваивается типу указателя.C++, присвоение не указательного типа указателю-члену класса шаблона

Он компилируется просто отлично (я использую GCC 5.3.0). И то, что меня действительно смутило, заключается в том, что компиляция зависит от параметра другого конструктора, val.

Это не имеет никакого эффекта в методах класса, только в конструкторах:

ошибка
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&)’

Почему это происходит? Где в стандарте описано это поведение?

+0

Я думаю, что это опечатка. Он компилируется отлично, потому что этот конструктор не вызван. – cpplearner

+0

Какой конструктор вызывается при построении параметра 'notAPointer'? – emlai

+0

Проблема с вашим конструктором не имеет ничего общего с назначением указателя или сопутствующими проблемами. Вы получите ту же ошибку с пустым куском конструктора. Конструктор копирования не может получить свой параметр по значению - это все, что есть в нем, и именно это пытается сказать ваш компилятор. – AnT

ответ

3

Ваш последний конструктор - copy constructor. Запрещается иметь конструктор копирования, который передает свой параметр по значению, так как иначе вы закончите бесконечную рекурсию.

Ошибка вы получаете аналогично

struct Foo 
{ 
    Foo(Foo); 
}; 

Live on Coliru

Более точно, в соответствии со стандартом:

12,8/2 Копирование и перемещение объектов класса [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.

Другие конструкторы/функции-члены выглядят нормально, потому что они не созданы, и код синтаксически правильный (теоретически Test<T> может иметь оператор преобразования до T* для некоторой специализации, и компилятор не может проверить это до создания экземпляра). Однако конструктор копирования должен иметь определенную форму, которая выполняется компилятором.

1

Все ваши примеры недействительны. Вы получите ошибку компиляции при попытке Instantiate любого метода:

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