模板重复实例化错误

以下代码编译产生如下错误:

Compiling: main.cpp
...cc1wtYYU.s: Assembler messages:
...cc1wtYYU.s:76: Error: symbol `__Z1gIXadL_Z1fvEEEvv' is already defined

代码:

void f()
{
}

typedef void(*F)();

template<F _F>
void g()
{
_F();
}

int main()
{
void f();
g<f>();
{
void f();
g<f>();
}
return 0;
}


如果不是模板实例化, g<f>()改为f()就OK.
如果去除一个void f()声明, 也会OK.
如果两个实例化在同一代码层次, 即去除那个大括号, 也OK.
就是g<f>模板实例化重复了, 好像是将两个f()声明当作了两个不同的函数.

gcc版本:

C:\Documents and Settings\jinqing>mingw32-g++.exe -v
Using built-in specs.
COLLECT_GCC=mingw32-g++.exe
COLLECT_LTO_WRAPPER=d:/mingw/bin/../libexec/gcc/mingw32/4.5.0/lto-wrapp
Target: mingw32
Configured with: ../gcc-4.5.0/configure --enable-languages=c,c++,ada,fo
c,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --ena
mp --disable-win32-registry --enable-libstdcxx-debug --enable-version-s
untime-libs --disable-werror --build=mingw32 --prefix=/mingw
Thread model: win32
gcc version 4.5.0 (GCC)


但VC可以通过。

可以确认为gcc的错误.
不过一查, 多年早有人发现并提出了该错误, 只是到现在还没有修复.

Bug 20357 - Multiply defined assembler symbols for template instantiations
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=20357

<think>嗯,用户问的是模板实例化,这个问题在C++里挺重要的。首先,我得回忆一下模板的基本概念。模板是用来生成代码的工具,分为函数模板和类模板实例化就是把模板变成具体的函数或类的过程。 用户可能已经了解模板的基本用法,但想深入理解实例化的机制。需要分清楚显式实例化和隐式实例化的区别。隐式实例化是编译器在需要的时候自动生成代码,比如当调用一个函数模板时,编译器会根据传入的参数类型生成对应的函数。而显式实例化则是开发者手动告诉编译器生成特定类型的实例,这样可以减少编译时间,特别是在大型项目中。 接下来要考虑实例化的时机。编译器在编译阶段处理模板实例化,链接器可能也会参与,尤其是在分离编译的情况下。这里可能需要解释模板代码通常放在头文件中的原因,因为编译器需要看到完整的定义才能实例化。 还要提到特化的问题,比如全特化和偏特化,虽然用户没有直接问,但作为模板实例化的一部分,可能相关。不过用户的问题主要集中在实例化本身,所以可能不需要深入特化,除非有必要。 另外,要注意实例化可能带来的代码膨胀问题。比如,多次实例化同一个类型的模板可能会导致生成多个相同的代码,影响程序大小。但现代编译器有优化手段,比如COMDAT,可以合并相同的实例。 用户可能在实际编程中遇到模板链接错误,比如在多个编译单元中实例化同一个模板导致重复定义,或者未实例化导致的链接错误。这时候显式实例化或者extern模板声明可能有帮助。 需要举例子说明隐式和显式实例化的用法。比如函数模板的调用导致隐式实例化,而显式实例化则使用template关键字声明。类模板实例化需要提供具体的模板参数。 最后总结一下实例化的应用场景和注意事项,帮助用户理解何时使用隐式,何时需要显式,以及如何管理模板代码的组织结构。确保回答结构清晰,分点说明,让用户能逐步理解模板实例化的机制和实际应用。</think>模板实例化C++模板编程的核心机制,其本质是编译器根据模板生成具体类型或函数的过程。以下从原理到实践的分步说明: 1. **模板基础概念** - 模板是代码的蓝图,分为函数模板(如`template<typename T> T max(T a, T b)`)和类模板(如`template<typename T> class vector`) - 未实例化模板本身不产生实际代码,仅作为生成代码的模具 2. **隐式实例化(Implicit Instantiation)** - 触发条件:当代码中实际使用模板时自动触发 - 函数模板示例: ```cpp template<typename T> T add(T a, T b) { return a + b; } int main() { add(3, 5); // 隐式实例化add<int> add(2.5, 3.7);// 隐式实例化add<double> } ``` - 类模板示例: ```cpp template<typename T> class Box { T content; public: void set(T t) { content = t; } }; Box<std::string> box; // 隐式实例化Box<std::string> ``` 3. **显式实例化(Explicit Instantiation)** - 目的:提前生成特定类型的模板实例,优化编译速度 - 语法格式: ```cpp template return_type function_name<type>(parameters); // 函数模板 template class ClassName<type>; // 类模板 ``` - 实际应用示例: ```cpp // 在.cpp文件中 template int add<int>(int, int); template class Box<std::string>; ``` 4. **实例化过程详解** - 编译器执行步骤: 1. 语法检查(模板定义阶段) 2. 类型推导(调用点分析) 3. 生成具体代码(实例化点) 4. 二次语法检查(验证生成代码的合法性) 5. **关键技术特性** - 惰性实例化:只实例化实际被使用的成员函数 ```cpp template<typename T> class Test { public: void used() {} // 会被实例化 void unused() {} // 不被实例化 }; ``` - 两阶段查找: - 模板定义阶段:检查与模板参数无关的语法 - 实例化阶段:验证模板参数相关的有效性 6. **代码组织最佳实践** - 模板定义通常需要放在头文件中 - 分离编译问题的解决方案: ```cpp // 显式实例化声明(.h) extern template class Box<int>; // 显式实例化定义(.cpp) template class Box<int>; ``` 7. **常见问题与调试** - 链接错误:未找到符号(缺少实例化) - 编译错误:类型不满足模板要求 - 解决方案:使用`static_assert`进行类型约束 ```cpp template<typename T> class Numeric { static_assert(std::is_arithmetic_v<T>, "Numeric requires arithmetic type"); }; ``` 8. **高级应用场景** - 模板元编程(TMP): ```cpp template<int N> struct Factorial { static const int value = N * Factorial<N-1>::value; }; ``` - 类型擦除技术(结合虚函数和模板) 理解模板实例化机制对于提升编译效率、优化代码结构和实现高级泛型编程模式至关重要。实际开发中需特别注意模板代码的组织方式,合理使用显式实例化来平衡编译时间与代码可维护性。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值