【问题标题】:C++ template specialization definitions shared across files跨文件共享的 C++ 模板特化定义
【发布时间】:2017-10-20 06:43:32
【问题描述】:

我有一个模板类“Extra”,定义在“extra.h”中,带有一个函数“doSomething”,并且我定义了“doSomething”的两个特化。两个不同的函数创建“Extra”类型的对象,每个对象都有一个不同的类型参数,并且每个都调用一个不同的特化。两个客户端函数“client1”和“client2”分别在两个文件“client1.cpp”和“client2.cpp”中定义。在第三个文件中,“main”调用“client1”,然后调用“client2”。现在,“client1.cpp”和“client2.cpp”都#include“extra.h”。我收到“doSomething”有 (2) 多个定义的链接器错误。当然,如果我将“client1”和“client2”的定义放在一个源文件中,我就不会有这个问题。有什么方法可以保留“client1”和“client2”的不同文件的排列?下面是我的代码。谢谢!

// extra.h
#ifndef EXTRA_H
#define EXTRA_H

template <typename T>
class Extra
{
    public:
        Extra(T);
        ~Extra();
        T doSomething(T);
    private:
        Extra() {}
        T m_value;
};

template <typename T> Extra<T>::Extra(T input) : m_value{input} {}

template <typename T> Extra<T>::~Extra() {}

template <> int Extra<int>::doSomething(int input)
{
    return input * m_value;
}

template <> double Extra<double>::doSomething(double input)
{
    return input + m_value;
}

template <typename T> T Extra<T>::doSomething(T input)
{
    return input;
}
#endif

// client1.cpp
#include "extra.h"
#include <iostream>

void client1()
{
    std::cout << "In client1." << std::endl;
    Extra<int> extra(2);
    int res = extra.doSomething(3);
    std::cout << "Value: " << res << std::endl;
}

// client2.cpp
#include "extra.h"
#include <iostream>

void client2()
{
    std::cout << "In client2." << std::endl;
    Extra<double> extra(2.0);
    double res = extra.doSomething(2.0);
    std::cout << "Value: " << res << std::endl;
}

// main.cpp
#include <iostream>

void client1();
void client2();

int main()
{
    std::cout << "In main." << std::endl;
    client1();
    client2();
    return 0;
}

为了完整起见,这里是我的链接器错误:

$ g++ -std=c++11 -o client client1.cpp client2.cpp main.cpp 
duplicate symbol __ZN5ExtraIiE11doSomethingEi in:
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client1-6fa7ed.o
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client2-387444.o
duplicate symbol __ZN5ExtraIdE11doSomethingEd in:
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client1-6fa7ed.o
    /var/folders/mf/jdvfkpms609206zpz8x5237r0000gn/T/client2-387444.o
ld: 2 duplicate symbols for architecture x86_64

【问题讨论】:

    标签: c++ templates linker linker-errors


    【解决方案1】:

    你需要标记你的doSomething inline:

    template <> inline int Extra<int>::doSomething(int input)
    {
        return input * m_value;
    }
    
    template <> inline double Extra<double>::doSomething(double input)
    {
        return input + m_value;
    }
    

    【讨论】:

    • 非常感谢!我已经试过了——我想——但我忘记了你必须标记定义 inline 而不仅仅是声明。
    • @AmittaiAviram 提出的解决方案问题已解决,对吧?
    • 是的!当然,这是一个玩具示例,所以我必须尝试将其应用于实际案例,这要复杂得多。我想一般原则是你必须内联每个函数特化,以便编译器将代码移动到调用者中,它不会再作为一个不同的函数定义出现在多个翻译单元中。再次感谢!
    • @AmittaiAviram 通常inline 确实是链接器的提示,以通知同一函数可能存在多个副本。当您直接在类中定义函数时,它被隐式视为内联。当您在头文件内部和某个类外部定义函数时(就像您所做的那样),您几乎总是必须将它们显式标记为内联以避免链接器错误。编译器是否内联它们是一个不同的问题。
    猜你喜欢
    • 1970-01-01
    • 2017-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2021-06-09
    • 2010-11-04
    相关资源
    最近更新 更多