2017-02-02 2 views
0

Betrachten Sie diese einfache Join-Funktion Implementierung.Vorlage Funktionen seltsam Linker Fehler

#include <iostream> 
#include <string> 

namespace detail { 
    template<typename... Args> 
    size_t calcSize(const Args&... args); 

    inline size_t calcSize(const std::string& head) { 
     return head.size(); 
    } 

    template<size_t N> 
    size_t calcSize(char const(&) [N]) { 
     return N - 1; 
    } 

    template<typename... Tail> 
    size_t calcSize(const std::string& head, const Tail&... tail) { 
     return head.size() + calcSize(tail...); 
    } 

    template<size_t N, typename... Tail> 
    size_t calcSize(char const(&) [N], const Tail&... tail) { 
     return N - 1 + calcSize(tail...); 
    } 

    template<typename... Args> 
    void fillResult(std::string& result, 
        size_t startIndex, 
        const Args&... args); 

    inline void fillResult(std::string& result, 
          size_t startIndex, 
          const std::string& head) { 
     for (size_t i = 0; i < head.size(); ++i) { 
      if (head[i] == '\0') { 
       break; 
      } 
      result[startIndex++] = head[i]; 
     } 
    } 

    template<size_t N> 
    void fillResult(std::string& result, 
        size_t startIndex, 
        char const(&head) [N]) { 
     for (size_t i = 0; i < N; ++i) { 
      if (head[i] == '\0') { 
       break; 
      } 
      result[startIndex++] = head[i]; 
     } 
    } 

    template<typename... Tail> 
    void fillResult(std::string& result, 
        size_t startIndex, 
        const std::string& head, 
        const Tail&... tail) { 
     for (size_t i = 0; i < head.size(); ++i) { 
      if (head[i] == '\0') { 
       break; 
      } 
      result[startIndex++] = head[i]; 
     } 
     fillResult(result, startIndex, tail...); 
    } 

    template<size_t N, typename... Tail> 
    void fillResult(std::string& result, 
        size_t startIndex, 
        char const(&head) [N], 
        const Tail&... tail) { 
     for (size_t i = 0; i < N; ++i) { 
      if (head[i] == '\0') { 
       break; 
      } 
      result[startIndex++] = head[i]; 
     } 
     fillResult(result, startIndex, tail...); 
    } 
} 

template<typename... Args> 
std::string join(const Args&... args) { 
    std::string result; 
    result.resize(detail::calcSize(args...)); 
    detail::fillResult(result, 0, args...); 
    return result; 
} 


int main() { 
    std::cout << join("ab", "cd", "ef", "gh") << std::endl; 
    std::cout << join(std::string("ab"), std::string("cd"), std::string("ef")) << std::endl; 
    std::cout << join(std::string("ab"), "cd") << std::endl; 
    //std::cout << join(std::string("ab"), "cd", "ef") << std::endl; 
    //std::cout << join(std::string("ab"), "cd", std::string("ef")) << std::endl; 
    return 0; 
} 

Es funktioniert gut für die drei ersten Zeilen in Main und schlägt mit Linker-Fehler, wenn Sie einen der letzten zwei Aufrufe auskommentieren. Versucht mit gcc 4.9 und clang mit dem gleichen Ergebnis. Kann jemand darauf hinweisen, was falsch ist? Hier ist ein Link http://coliru.stacked-crooked.com/a/f55aa64fb4861e43

Antwort

1

Ich denke, das ist im Grunde ein schlecht gebildet Programm coliru, weil Sie eine Überlastung am Ende mit, die nicht verwendet werden, wenn alle Überlastungen zum Zeitpunkt der Verwendung sichtbar gewesen waren. Dies liegt daran, dass die gewünschte Überladung noch nicht an dem Punkt deklariert ist, an dem sie benötigt wird. Um dies zu beheben, fügen Sie einfach alle Erklärungen vorne:

namespace detail { 

template<typename... Args> 
size_t calcSize(const Args&... args); 

template<size_t N, typename... Tail> 
size_t calcSize(char const(&) [N], const Tail&... tail); 

template<typename... Tail> 
size_t calcSize(const std::string& head, const Tail&... tail); 

template<typename... Tail> 
void fillResult(std::string& result, 
       size_t startIndex, 
       const std::string& head, 
       const Tail&... tail); 

template<size_t N, typename... Tail> 
void fillResult(std::string& result, 
       size_t startIndex, 
       char const(&head) [N], 
       const Tail&... tail); 
+0

[Demo] (http://coliru.stacked-crooked.com/a/db7d6473fedd0cb5) –

+0

Danke, es funktioniert jetzt. Aber ich verstehe immer noch nicht, warum es ein ** Linker ** Fehler statt eines Kompilierungsfehlers ist. – user6256186

+0

@ user6256186: Es ist schlecht geformt, keine Diagnose erforderlich. Ihr Programm wählt die erste Funktionsvorlage 'template size_t calcSize (constArgs & ... args)' im rekursiven Aufruf aus, nicht die beabsichtigte Überladung und (die gewählte Spezialisierung von) diese Vorlage ist nicht definiert. –