2016-03-27 31 views
5

Birkaç günlüğüne başımı ağrıyor, bakıyorum ve açık kaynak kodlu projelerde benzer kodlar arıyordum: Yanlış yapıyorum.Arkadaş sınıfının içinde ilan edilmiş şablon işlevi tanımlanamayan bir simge neden oluyor Sembol bağlantı hatası

Esasen

, aşağıdaki kod verilir (özü damıtılarak): Bu gibi kodu kullanılan

#include <iostream> 


using std::cout; 
using std::endl; 
using std::string; 

template <typename T> 
class Node { 
    T value_; 
public: 
    Node(const T& value) : value_(value) {} 
    T const value() const { return value_; } 

    friend 
    std::ostream& operator <<(std::ostream& out, const Node<T>& node); 

    Node<T> operator +(const Node<T>& other) { 
     return Node(value() + other.value()); 
    } 
}; 


template <typename T> 
std::ostream& operator <<(std::ostream& out, const Node<T>& node) { 
    return out << node.value(); 
} 

:

int main(int argc, char* argv[]) { 

    Node<string> node("node X"); 
    cout << node << endl; 

    Node<int> three(3); 
    cout << three << endl; 

    return EXIT_SUCCESS; 
} 

aşağıdaki bağlayıcı hata:

Undefined symbols for architecture x86_64: 
    "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Node<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&)", referenced from: 
     _main in StlPractice.cpp.o 
    "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Node<int> const&)", referenced from: 
     _main in StlPractice.cpp.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Anlatabildiğim kadarıyla, yukarıdakilerin hepsi yasal C++ 11 kodudur; şablon iyi tanımlanmış ve yine de, linker'ın onu bulma yeteneğinden kaçış gibi görünüyor.

OS X üzerinde bu kuruludur kullanarak cmake: Ne verir

cmake_minimum_required(VERSION 3.3) 
project(simple_template) 

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 

set(SOURCE_FILES src/simple_template.cpp) 

add_executable(simple ${SOURCE_FILES}) 

?

Şimdiden teşekkürler!

$ clang++ src/simple_template.cpp 
Undefined symbols for architecture x86_64: 
    "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Node<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > const&)", referenced from: 
     _main in StlPractice-e20370.o 
    "operator<<(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, Node<int> const&)", referenced from: 
     _main in StlPractice-e20370.o 
ld: symbol(s) not found for architecture x86_64 
clang: error: linker command failed with exit code 1 (use -v to see invocation) 
+0

Evet, bu derleme ve içerir "normal şüpheli" iostream 'çoğunlukla; Ben cmake kullanıyorum - soruya ekliyorum. Teşekkürler, bağlantı için, arada sırada kontrol edeceğim. – Marco

cevap

6

arkadaşı olmayan şablon işlevi olduğu gibi sınıf içinde beyan ve sınıfın dışında tanım şablonu şu şekildedir: Söz ardından

Güncelleme, şunlarla, aynı sonucu koştu ettik işlev, eşleşmiyorlar. Ve overload resolution için, şablon işlev özelliğinden önce şablon olmayan işlev seçilecektir, bu nedenle tanımlanmamış semboller bağlantı hatası oluştu.

Şablon fonksiyonu olarak beyanı değişebilir

:

template<typename X> 
friend std::ostream& operator <<(std::ostream& out, const Node<X>& node); 

LIVE

veya sınıf içindeki işlevi tanımlayın:

friend 
std::ostream& operator <<(std::ostream& out, const Node<T>& node) { return out << node.value(); } 

LIVE

+0

Teşekkürler! Bu tam olarak ** oldu - Ben sadece "suçlu", "arkadaşın" işlevinde olduğu gibi, sınıf içindeki beyanın kaldırılması gibi keşfettim, hepsi işe yaradı. Fark etmediğim şey, 'template'i sınıf tanımının içine eklemem gerektiğiydi. – Marco

+1

@Marco Evet, bunun bir şablon işlevi olduğunu söylemeniz gerekir. Şablon dışı işlev ve şablon işlevi aynı değil. – songyuanyao

1

Sizin tanımınız bir eşleşir templated arkadaş declar sahip olmadığın ation.

Bazen sadece çok spesifik Node<T> türlerine izin vermek istiyorsunuz, bu şekilde bunu nasıl yapacaksınız.

http://rextester.com/GZKCJQ35441

template <typename T> 
class Node { 
    T value_; 
public: 
    Node(const T& value) : value_(value) {} 
    T const value() const { return value_; } 

    friend 
    std::ostream& operator <<(std::ostream& out, const Node<T>& node); 

    Node<T> operator +(const Node<T>& other) { 
     return Node(value() + other.value()); 
    } 
}; 

std::ostream& operator <<(std::ostream& out, const Node<int>& node) { return out << node.value_; } 
std::ostream& operator <<(std::ostream& out, const Node<string>& node) { return out << node.value_; } 

Veya basitçe tanımını değiştirebilir ve şablonlu-arkadaş olun.

0

sınıf şablonuna Node<T> için operator<< aşırı kabaca üç yolu vardır: Bir public üye işlev value() sağlamak yana

  1. , değil aslında yapmak bir friend ancak bunun yerine non olmayan bir arkadaşı tanımlayabilirsiniz gerek tamamen Node<T>

Live Example 1 arasında public arayüz açısından -Member işlevi şablon:

template <typename T> 
std::ostream& operator <<(std::ostream& out, const Node<T>& node) { 
    return out << node.value(); 
} 
Eğer sınıfının bir (ve bu sınıf şablonu çevreleyen ad alanında yaşayacak) tanımlayan üye olmayan bir işlev kullanabilirsiniz, Node<T> her uzmanlık için

    Live Example 2:

    template <typename T> 
    class Node {   
        // generates a non-template operator<< for this T 
        friend std::ostream& operator<<(std::ostream& out, const Node<T>& node) { 
         return out << node.value_; 
        } 
    }; 
    
    Node<T> her uzmanlık için
  • , bir fu eşlik eden bir uzmanlık tanımlayabilir
      operator<< <> sözdizimi (veya eşdeğeri operator<< <T> sözdizimi)

    Live Example 3

    // forward declare to make function declaration possible 
    template <typename T> 
    class Node; 
    
    // declaration 
    template <typename T> 
    std::ostream& operator <<(std::ostream& out, const Node<T>& node); 
    
    template <typename T> 
    class Node { 
        // refers to a full specialization for this particular T 
        friend std::ostream& operator<< <>(std::ostream& out, const Node<T>& node);  
        // note: this relies on template argument deduction in declarations 
        // can also specify the template argument with operator<< <T>"  
    }; 
    
    // definition 
    template <typename T> 
    std::ostream& operator <<(std::ostream& out, const Node<T>& node) { 
        return out << node.value_; 
    } 
    

    sınıf şablonu Node<T> bir template <typename U> operator<<(std::ostream&, const Node<U>&) her uzmanlık arkadaşlık ile dördüncü ihtimali de vardır kullanılarak friend bildirerek nction şablonu (@songyuanyao tarafından cevap ilk seçenek) ama bence bu overkill.

    Genel arabirim açısından G/Ç'yi ve diğer seçenek 2 veya 3'ü ifade ederseniz seçenek 1'i kullanmanızı öneririm. Bu ikisi çoğunlukla eşdeğerdir, argüman indirimi sırasında isim aramasında bazı küçük farklılıklar ve örtük dönüşümler.