微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

带有浮点数的函数模板的多个定义,试图解决链接器错误

如何解决带有浮点数的函数模板的多个定义,试图解决链接器错误

我正在研究一组函数模板并且编译很好。您可以看到它们在编译器资源管理器上运行 here ......问题是当我尝试在我的项目中将它与 T = float 一起使用时,由于多个定义而无法链接......我已经尝试了各种事情,似乎无法解决这个问题...

这是我的头文件

cstr.h

#pragma once

#include <stdint.h>

const uint8_t default_decimal_places = 8;

template<typename T>
const char* to_string(T value) {
    static char output_buffer[128];

    uint8_t negative = 0;
    bool isNegative = false;
    if (value < 0) {
        isNegative = true;
        negative = 1;
        value *= -1;
        output_buffer[0] = '-';
    }

    uint8_t size = 0;
    T sizeTest = value;
    while (sizeTest / 10 > 0) {
        sizeTest /= 10;
        size++;
    }

    uint8_t idx = 0;
    if (isNegative) {
        while (value / 10 > 0) {
            uint8_t remainder = value % 10;
            value /= 10;
            output_buffer[negative + size - idx] = remainder + '0';
            idx++;
        }
        uint8_t remainder = value % 10;
        output_buffer[negative + size - idx] = remainder + '0';
        output_buffer[negative + size + 1] = 0;
    }
    else {
        while (value / 10 > 0) {
            uint8_t remainder = value % 10;
            value /= 10;
            output_buffer[size - idx] = remainder + '0';
            idx++;
        }
        uint8_t remainder = value % 10;
        output_buffer[size - idx] = remainder + '0';
        output_buffer[size + 1] = 0;
    }

    return output_buffer;
}

template<typename T>
const char* to_string(T value,uint8_t decimal_places) {
    if (decimal_places > 20) decimal_places = 20;

    static char output_double_buffer[128];
    char* intPtr = (char*)to_string((int64_t)value);
    char* doublePtr = output_double_buffer;

    if (value < 0) {
        value *= -1;
    }

    while(*intPtr != 0) {
        *doublePtr = *intPtr;
        intPtr++;
        doublePtr++;
    }

    *doublePtr = '.';
    doublePtr++;

    T newValue = value - (int)value;

    for (uint8_t i = 0; i < decimal_places; i++) {
        newValue *= 10;
        *doublePtr = (int)newValue + '0';
        newValue -= (int)newValue;
        doublePtr++;
    }

    *doublePtr = 0;
    return output_double_buffer;
}

template<>
inline const char* to_string<float>(float value,uint8_t decimal_places) {
    if (decimal_places > 14) decimal_places = 14;

    static char output_float_buffer[128];
    char* intPtr = (char*)to_string((int64_t)value);
    char* floatPtr = output_float_buffer;

    if (value < 0) {
        value *= -1;
    }

    while(*intPtr != 0) {
        *floatPtr = *intPtr;
        intPtr++;
        floatPtr++;
    }

    *floatPtr = '.';
    floatPtr++;

    float newValue = value - (int)value;

    for (uint8_t i = 0; i < decimal_places; i++) {
        newValue *= 10;
        *floatPtr = (int)newValue + '0';
        newValue -= (int)newValue;
        floatPtr++;
    }

    *floatPtr = 'f';
    floatPtr++;
    *floatPtr = 0;
    return output_float_buffer;
}

这是cpp文件...

#include "cstr.h"

调用它们的类...

BasicRenderer.cpp

void BasicRenderer::Print(double val,uint8_t decimal_places) {
    Print(to_string(val,decimal_places));
}

void BasicRenderer::Print(float val,decimal_places));
}

但是,当我在我的应用程序中运行它时...... GCC 给了我这个链接错误......

skilz420@skilz-PC:~/skilzOS/kernel$ make kernel
!==== COMPILING src/cstr.cpp
gcc -ffreestanding -fshort-wchar -c src/cstr.cpp -o lib/cstr.o
!==== LINKING
ld -T kernel.ld -static -Bsymbolic -nostdlib -o bin/kernel.elf  lib/kernel.o  lib/cstr.o  lib/BasicRenderer.o
ld: lib/BasicRenderer.o: in function `char const* to_string<float>(float,unsigned char)':
BasicRenderer.cpp:(.text+0x0): multiple deFinition of `char const* to_string<float>(float,unsigned char)'; lib/kernel.o:kernel.cpp:(.text+0x0): first defined here
make: *** [Makefile:33: link] Error 1
skilz420@skilz-PC:~/skilzOS/kernel$ 

我什至尝试将它的定义移动到 CPP 文件中,将其内联等等......这是一个漫长的夜晚,我只想在我称之为夜晚之前让它工作......{ {1}} 本身工作正常,但是当我尝试添加并专门化 double 变体时会这样做,是的,float 的行为与 float 不同。

解决方法

好的,喝完酒回来……我发现了问题所在……它在头文件中的方式很好。问题出在另一个使用它的班级中。例如...

void BasicRenderer::Print(const char* str ) {
    // code implementation
}

void BasicRenderer::Print(double val,uint8_t decimal_places) {
    Print(to_string(val,decimal_places);
}

void BasicRenderer::Print(float val,uint8_t decimal_places);
    Print(to_string(val,decimal_places);
}

这就是导致链接器错误的原因...

我不得不将它们更改为以下内容...

void BasicRenderer::Print(double val,uint8_t decimal_places) {
    Print(to_string<double>(val,uint8_t decimal_places);
    Print(to_string<float>(val,decimal_places);
}

现在他们都工作了。我必须明确地实例化它们......这发生在我重构我的代码到我开始模板化这些转换和打印函数的地方......并且将近一个小时我盯着这个问题挠头......--eh-- template<T = float> = headaches...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。