2015-01-29 3 views
2

Я не понимаю необходимости static_cast в следующей C++ коды сниппета (протестировано с GCC-4.7):C++ поиск имена зависят от декларации методы шаблона

#include <cstdio> 

class Interface 
{ 
public: 
    virtual void g(class C* intf) = 0; 

    virtual ~Interface() {} 
}; 

class C 
{ 
public: 
    void f(int& value) 
    { 
     printf("%d\n", value); 
    } 

    void f(Interface* i) 
    { 
     i->g(this); 
    } 

    template <typename T> 
    void f(T& t); 
    //void f(class Implementation& i); 
}; 

class Implementation : public Interface 
{ 
public: 
    Implementation(int value_) : value(value_) {} 
    void g(C* intf) 
    { 
     intf->f(value); 
    } 

private: 
    int value; 
}; 

int main() 
{ 
    C a; 
    Implementation* b = new Implementation(1); 

    //a.f(b); // This won't work: undefined reference to `void C::f<Implementation*>(Implementation*&)' 
    a.f(static_cast<Interface*>(b)); 

    delete b; 

    return 0; 
} 

Если я опускаю static_cast, Я получаю ошибку компоновщика, потому что он хочет использовать:

template <typename T> 
void f(T& t); 

вместо:

void f(Interface* i); 

с другой стороны, если я Repl асе шаблонного метода следующее (закомментирована в приведенном выше фрагменте кода):

void f(class Implementation& i); 

, то я не получаю ошибки, и я могу видеть, что «правильный» метод вызывается во время выполнения (то есть:

void f(Interface* i); 

).

Почему объявление метода шаблона влияет на поиск имени? Большое спасибо заранее,

+2

Похоже, вы спрашиваете, почему идеальное совпадение предпочтительнее, чем несовершенное соответствие, требующее преобразования в указатель базового класса. Ответ довольно очевиден - лучшие матчи лучше. –

ответ

4

При выполнении разрешения перегрузки для a.f(b), компилятор отмечает два факта:

во-первых, Вы пытаетесь вызвать f с Lvalue типа Implementation*.

Во-вторых, три функции находятся в наборе перегрузки: C::f(int&) и C::f(Interface*) и C::f<Implementation*>(Implementation*&). Обратите внимание, что template включен, поскольку его параметр шаблона можно вывести из аргумента, с которым он вызывается.

Теперь компилятор начинает проверять, какая функция подходит «лучше»:

  • C::f(int&) нельзя назвать с этим аргументом на всех.
  • C::f(Interface*) можно назвать, но требует одного стандартного преобразования (указателя на полученный -> указатель на базу)
  • C::f<Implementation*>(Implementation*&) можно назвать без любых преобразований

Таким образом, шаблон достаточно просто подходит лучше всего. Однако, поскольку вы не определили реализацию для шаблона, позже компоновщик выдает ошибки с сообщением об ошибке, что он не может найти функцию, которую вы пытаетесь вызвать.