模板函数奇怪链接器错误

时间:2017-02-02 10:47:48

标签: c++ templates linker

考虑这个简单的连接函数实现。

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

它适用于main中的三个第一行,如果取消注释两个最后一次调用中的任何一个,则会因链接器错误而失败。尝试用gcc 4.9和clang得到相同的结果。任何人都可以指出什么是错的? 以下是coliru http://coliru.stacked-crooked.com/a/f55aa64fb4861e43

的链接

1 个答案:

答案 0 :(得分:1)

我认为这基本上是一个格式错误的程序,因为如果在使用时看到所有重载,你最终会使用不会被使用的重载。这是因为您想要的重载在实际需要时尚未实际声明。要解决此问题,只需预先添加所有声明:

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);
相关问题